html_url,issue_url,id,node_id,user,created_at,updated_at,author_association,body,reactions,issue,performed_via_github_app https://github.com/simonw/datasette/issues/843#issuecomment-643676314,https://api.github.com/repos/simonw/datasette/issues/843,643676314,MDEyOklzc3VlQ29tbWVudDY0MzY3NjMxNA==,9599,2020-06-13T20:47:37Z,2020-06-13T20:47:37Z,OWNER,I can use this action: https://github.com/codecov/codecov-action,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638229448, https://github.com/simonw/datasette/issues/843#issuecomment-643676069,https://api.github.com/repos/simonw/datasette/issues/843,643676069,MDEyOklzc3VlQ29tbWVudDY0MzY3NjA2OQ==,9599,2020-06-13T20:45:29Z,2020-06-13T20:45:29Z,OWNER,I set up https://codecov.io/gh/simonw/datasette/settings and added a `CODECOV_TOKEN` to the GitHub Actions secrets for this repo.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638229448, https://github.com/simonw/datasette/issues/842#issuecomment-643663005,https://api.github.com/repos/simonw/datasette/issues/842,643663005,MDEyOklzc3VlQ29tbWVudDY0MzY2MzAwNQ==,9599,2020-06-13T18:51:57Z,2020-06-13T18:51:57Z,OWNER,"Two potential designs: - `_actor_id`, `_request_ip`, `_now_timestamp` - so special reserved parameters - a SQL function: `update blah set up = special('ip')` I fee the first would be easier to implement.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638212085, https://github.com/simonw/datasette/issues/841#issuecomment-643661125,https://api.github.com/repos/simonw/datasette/issues/841,643661125,MDEyOklzc3VlQ29tbWVudDY0MzY2MTEyNQ==,9599,2020-06-13T18:35:30Z,2020-06-13T18:36:50Z,OWNER,"I ran export CODECOV_TOKEN=""f7935cad..."", then ran this: ``` datasette $ bash <(curl -s https://codecov.io/bash) _____ _ / ____| | | | | ___ __| | ___ ___ _____ __ | | / _ \ / _` |/ _ \/ __/ _ \ \ / / | |___| (_) | (_| | __/ (_| (_) \ V / \_____\___/ \__,_|\___|\___\___/ \_/ Bash-20200602-f809a24 x> No CI provider detected. Testing inside Docker? http://docs.codecov.io/docs/testing-with-docker Testing with Tox? https://docs.codecov.io/docs/python#section-testing-with-tox project root: . --> token set from env Yaml not found, that's ok! Learn more at http://docs.codecov.io/docs/codecov-yaml ==> Running gcov in . (disable via -X gcov) ==> Searching for coverage reports in: + . -> Found 1 reports ==> Detecting git/mercurial file structure ==> Reading reports + ./coverage.xml bytes=139174 ==> Appending adjustments https://docs.codecov.io/docs/fixing-reports -> No adjustments found ==> Gzipping contents ==> Uploading reports url: https://codecov.io query: branch=master&commit=0e49842e227a0f1f69d48108c87d17fe0379e548&build=&build_url=&name=&tag=&slug=simonw%2Fdatasette&service=&flags=&pr=&job= -> Pinging Codecov https://codecov.io/upload/v4?package=bash-20200602-f809a24&token=secret&branch=master&commit=0e49842e227a0f1f69d48108c87d17fe0379e548&build=&build_url=&name=&tag=&slug=simonw%2Fdatasette&service=&flags=&pr=&job= -> Uploading -> View reports at https://codecov.io/github/simonw/datasette/commit/0e49842e227a0f1f69d48108c87d17fe0379e548 ``` But https://codecov.io/github/simonw/datasette/commit/0e49842e227a0f1f69d48108c87d17fe0379e548 is a 404, so it doesn't seem to have worked? UPDATE: It works now, took about 30 seconds before the report showed up at that URL.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638104520, https://github.com/simonw/datasette/issues/841#issuecomment-643660757,https://api.github.com/repos/simonw/datasette/issues/841,643660757,MDEyOklzc3VlQ29tbWVudDY0MzY2MDc1Nw==,9599,2020-06-13T18:32:20Z,2020-06-13T18:32:20Z,OWNER,"Looking at options for publishing coverage reports: * https://github.com/codecov/codecov-action * https://github.com/coveralls-clients/coveralls-python I'm going to try https://codecov.io/","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638104520, https://github.com/simonw/datasette/issues/841#issuecomment-643660427,https://api.github.com/repos/simonw/datasette/issues/841,643660427,MDEyOklzc3VlQ29tbWVudDY0MzY2MDQyNw==,9599,2020-06-13T18:29:30Z,2020-06-13T18:29:36Z,OWNER,"This one looks easy enough to fix: ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638104520, https://github.com/simonw/datasette/issues/841#issuecomment-643658036,https://api.github.com/repos/simonw/datasette/issues/841,643658036,MDEyOklzc3VlQ29tbWVudDY0MzY1ODAzNg==,9599,2020-06-13T18:08:13Z,2020-06-13T18:08:13Z,OWNER,"From digging through that report it looks like the majority stuff that isn't fully covered is corner-cases... which are the kind of things I really do want the tests to catch. I'm not entirely ready to commit to 100%, but I'm going to start digging through and seeing how close I can get. If I can get to 98% (I'm on 91% already) I may as well push all the way to 100.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638104520, https://github.com/simonw/datasette/issues/841#issuecomment-643657287,https://api.github.com/repos/simonw/datasette/issues/841,643657287,MDEyOklzc3VlQ29tbWVudDY0MzY1NzI4Nw==,9599,2020-06-13T18:01:39Z,2020-06-13T18:01:39Z,OWNER,Added `--cov-report html` and got this report: https://static.simonwillison.net/static/2020/htmlcov-issue-841/index.html,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638104520, https://github.com/simonw/datasette/issues/841#issuecomment-643656053,https://api.github.com/repos/simonw/datasette/issues/841,643656053,MDEyOklzc3VlQ29tbWVudDY0MzY1NjA1Mw==,9599,2020-06-13T17:50:34Z,2020-06-13T17:50:34Z,OWNER,"Added a `.coveragerc` file: ``` [run] omit = datasette/_version.py, datasette/utils/shutil_backport.py ``` And ran again: `pytest --cov=datasette --cov-config=.coveragerc` ``` Name Stmts Miss Cover ------------------------------------------------------ datasette/__init__.py 3 0 100% datasette/__main__.py 3 3 0% datasette/actor_auth_cookie.py 19 3 84% datasette/app.py 499 27 95% datasette/cli.py 157 45 71% datasette/database.py 233 17 93% datasette/default_permissions.py 39 0 100% datasette/facets.py 209 24 89% datasette/filters.py 122 7 94% datasette/hookspecs.py 19 0 100% datasette/inspect.py 37 23 38% datasette/plugins.py 34 6 82% datasette/publish/__init__.py 0 0 100% datasette/publish/cloudrun.py 55 2 96% datasette/publish/common.py 19 1 95% datasette/publish/heroku.py 95 13 86% datasette/renderer.py 63 4 94% datasette/sql_functions.py 4 0 100% datasette/tracer.py 85 16 81% datasette/utils/__init__.py 503 31 94% datasette/utils/asgi.py 253 25 90% datasette/version.py 4 0 100% datasette/views/__init__.py 0 0 100% datasette/views/base.py 288 19 93% datasette/views/database.py 120 2 98% datasette/views/index.py 57 2 96% datasette/views/special.py 72 16 78% datasette/views/table.py 418 18 96% ------------------------------------------------------ TOTAL 3410 304 91% ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638104520, https://github.com/simonw/datasette/issues/841#issuecomment-643655108,https://api.github.com/repos/simonw/datasette/issues/841,643655108,MDEyOklzc3VlQ29tbWVudDY0MzY1NTEwOA==,9599,2020-06-13T17:43:15Z,2020-06-13T17:43:15Z,OWNER,"Using https://pypi.org/project/pytest-cov/ and running `pytest --cov=datasette`: ``` ---------- coverage: platform darwin, python 3.7.7-final-0 ----------- Name Stmts Miss Cover -------------------------------------------------------- datasette/__init__.py 3 0 100% datasette/__main__.py 3 3 0% datasette/_version.py 277 152 45% datasette/actor_auth_cookie.py 19 3 84% datasette/app.py 499 27 95% datasette/cli.py 157 45 71% datasette/database.py 233 17 93% datasette/default_permissions.py 39 0 100% datasette/facets.py 209 24 89% datasette/filters.py 122 7 94% datasette/hookspecs.py 19 0 100% datasette/inspect.py 37 23 38% datasette/plugins.py 34 6 82% datasette/publish/__init__.py 0 0 100% datasette/publish/cloudrun.py 55 2 96% datasette/publish/common.py 19 1 95% datasette/publish/heroku.py 95 13 86% datasette/renderer.py 63 4 94% datasette/sql_functions.py 4 0 100% datasette/tracer.py 85 16 81% datasette/utils/__init__.py 503 31 94% datasette/utils/asgi.py 253 25 90% datasette/utils/shutil_backport.py 44 40 9% datasette/version.py 4 0 100% datasette/views/__init__.py 0 0 100% datasette/views/base.py 288 19 93% datasette/views/database.py 120 2 98% datasette/views/index.py 57 2 96% datasette/views/special.py 72 16 78% datasette/views/table.py 418 18 96% -------------------------------------------------------- TOTAL 3731 496 87% ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638104520, https://github.com/simonw/datasette/issues/834#issuecomment-643648359,https://api.github.com/repos/simonw/datasette/issues/834,643648359,MDEyOklzc3VlQ29tbWVudDY0MzY0ODM1OQ==,9599,2020-06-13T16:47:29Z,2020-06-13T16:47:29Z,OWNER,"Implementing this is proving surprisingly tricky, because of the need to be able to optionally `await` the returned value. It's a bit of a fiddle to get this to work within unit tests because they run in non-async functions - due to this cunning `async_to_sync` usage in the test client: https://github.com/simonw/datasette/blob/b906030235efbdff536405d66078f4868ce0d3bd/tests/fixtures.py#L115-L133 I could switch to using `async def test_*` functions decorated with `@pytest.mark.asyncio` but I'd rather not re-engineer the entire test suite just for this one feature, so I'll try to find another way.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637342551, https://github.com/simonw/datasette/issues/841#issuecomment-643576372,https://api.github.com/repos/simonw/datasette/issues/841,643576372,MDEyOklzc3VlQ29tbWVudDY0MzU3NjM3Mg==,9599,2020-06-13T06:08:34Z,2020-06-13T06:08:34Z,OWNER,Starlette achieves this. https://github.com/encode/starlette,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",638104520, https://github.com/simonw/datasette/issues/834#issuecomment-643510240,https://api.github.com/repos/simonw/datasette/issues/834,643510240,MDEyOklzc3VlQ29tbWVudDY0MzUxMDI0MA==,9599,2020-06-12T22:40:26Z,2020-06-12T22:40:26Z,OWNER,Another use-case: plugins that need their own database with the correct tables. They can write to the database on startup to create their tables.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637342551, https://github.com/simonw/datasette/issues/834#issuecomment-643509358,https://api.github.com/repos/simonw/datasette/issues/834,643509358,MDEyOklzc3VlQ29tbWVudDY0MzUwOTM1OA==,9599,2020-06-12T22:36:37Z,2020-06-12T22:36:37Z,OWNER,This should be able to optionally return an async function which is then awaited.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637342551, https://github.com/simonw/datasette/issues/805#issuecomment-643501428,https://api.github.com/repos/simonw/datasette/issues/805,643501428,MDEyOklzc3VlQ29tbWVudDY0MzUwMTQyOA==,9599,2020-06-12T22:06:08Z,2020-06-12T22:06:08Z,OWNER,"This needs the `startup` hook, see https://github.com/simonw/datasette/issues/834#issuecomment-643501064","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632724154, https://github.com/simonw/datasette/issues/834#issuecomment-643501064,https://api.github.com/repos/simonw/datasette/issues/834,643501064,MDEyOklzc3VlQ29tbWVudDY0MzUwMTA2NA==,9599,2020-06-12T22:04:43Z,2020-06-12T22:04:43Z,OWNER,Another use-case for this: I want to use the `--root` option on Glitch but it gives me a 127.0.0.1 URL. Glitch has a `PROJECT_DOMAIN` environment variable which tells me the URL. A `datasette-glitch` plugin could use a `startup` hook to output the correct login URL.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637342551, https://github.com/simonw/datasette/issues/840#issuecomment-643454625,https://api.github.com/repos/simonw/datasette/issues/840,643454625,MDEyOklzc3VlQ29tbWVudDY0MzQ1NDYyNQ==,9599,2020-06-12T19:47:38Z,2020-06-12T19:47:53Z,OWNER,"Another problem: what to display in the ""you are logged in as"", since we don't dictate an actor design. I'm going to use a includes template for this that can easily be over-ridden by administrators or by plugins. The default will look for the first available of the following keys: - display - name - username - login - id","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637966833, https://github.com/simonw/datasette/issues/840#issuecomment-643453128,https://api.github.com/repos/simonw/datasette/issues/840,643453128,MDEyOklzc3VlQ29tbWVudDY0MzQ1MzEyOA==,9599,2020-06-12T19:43:15Z,2020-06-12T19:43:15Z,OWNER,"I don't like how this often involves a logout link that can be maliciously activated. I'm going to use a CSRF protected form button styled to look like a link instead.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637966833, https://github.com/dogsheep/github-to-sqlite/issues/40#issuecomment-643414646,https://api.github.com/repos/dogsheep/github-to-sqlite/issues/40,643414646,MDEyOklzc3VlQ29tbWVudDY0MzQxNDY0Ng==,9599,2020-06-12T18:06:48Z,2020-06-12T18:06:48Z,MEMBER,That fixed it.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637899539, https://github.com/simonw/sqlite-utils/issues/115#issuecomment-643406939,https://api.github.com/repos/simonw/sqlite-utils/issues/115,643406939,MDEyOklzc3VlQ29tbWVudDY0MzQwNjkzOQ==,9599,2020-06-12T17:51:11Z,2020-06-12T17:51:11Z,OWNER,https://github.com/simonw/sqlite-utils/blob/03ee97d2258254581bea72842518904fc1cbe60f/tests/test_cli.py#L1112-L1128,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637889964, https://github.com/dogsheep/github-to-sqlite/issues/40#issuecomment-643393506,https://api.github.com/repos/dogsheep/github-to-sqlite/issues/40,643393506,MDEyOklzc3VlQ29tbWVudDY0MzM5MzUwNg==,9599,2020-06-12T17:21:14Z,2020-06-12T17:21:14Z,MEMBER,"I only install SQLite for this: https://github.com/dogsheep/github-to-sqlite/blob/c0d54e0260468be38152293df5abd775c068495d/.github/workflows/deploy-demo.yml#L77-L78 I'm going to remove the need to install sqlite3 by making this possible with sqlite-utils: https://github.com/simonw/sqlite-utils/issues/115","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637899539, https://github.com/simonw/datasette/issues/838#issuecomment-643083451,https://api.github.com/repos/simonw/datasette/issues/838,643083451,MDEyOklzc3VlQ29tbWVudDY0MzA4MzQ1MQ==,79913,2020-06-12T06:04:14Z,2020-06-12T06:04:14Z,NONE,"Hmm, I haven't tried removing `ProxyPassReverse`, but it doesn't touch the HTML, which is the issue I'm seeing. You can read the [documentation here](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxypassreverse). `ProxyPassReverse` is a standard directive when proxying with Apache. I've used it dozens of times with other applications. Looking a little more at the code, I think the issue here is that the behaviour of `base_url` makes sense when Datasette is _mounted_ at a path within a larger application, but not when HTTP requests are being _proxied_ to it. In a _mount_ situation, it is perfectly fine to construct URLs reusing the domain and path from the request. In a _proxy_ situation, it never is, as the domain and path in the request are not the domain and path that the non-proxy client actually needs to use. That is, links which include the Apache → Datasette request origin, `localhost:8001`, instead of the browser → Apache request origin, `example.com`, will be broken. The tests you pointed to also reflect this in two ways: 1. They strip a leading `http://localhost`, allowing such URLs in the facet links to pass, but inclusion of that in a proxy situation would mean the URL is broken. 2. The test client emits direct ASGI events instead of actual proxied HTTP requests. The headers of these ASGI events don't reflect the way an HTTP proxy works; instead they pass through the original request path which contains `base_url`. This works because Datasette responds to requests equivalently at either `/…` or `/{base_url}/…`, which makes some sense in a _mount_ situation but is unconventional (albeit workable) for a proxied app. Apps that support being proxied automatically support being mounted, but apps that only support being mounted don't automatically support being proxied.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637395097, https://github.com/simonw/datasette/issues/806#issuecomment-643010591,https://api.github.com/repos/simonw/datasette/issues/806,643010591,MDEyOklzc3VlQ29tbWVudDY0MzAxMDU5MQ==,9599,2020-06-12T01:13:06Z,2020-06-12T01:13:06Z,OWNER,Tests are passing again: https://github.com/simonw/datasette/commit/9ae0d483ead93c0832142e5dc85959ae3c8f73ea,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632753851, https://github.com/simonw/datasette/issues/806#issuecomment-643000948,https://api.github.com/repos/simonw/datasette/issues/806,643000948,MDEyOklzc3VlQ29tbWVudDY0MzAwMDk0OA==,9599,2020-06-12T00:34:21Z,2020-06-12T00:34:21Z,OWNER,I'm going to add https://github.com/simonw/datasette-auth-tokens and https://github.com/simonw/datasette-permissions-sql to the documentation and release notes in a few places.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632753851, https://github.com/simonw/datasette/issues/806#issuecomment-642998097,https://api.github.com/repos/simonw/datasette/issues/806,642998097,MDEyOklzc3VlQ29tbWVudDY0Mjk5ODA5Nw==,9599,2020-06-12T00:26:00Z,2020-06-12T00:26:00Z,OWNER,"OK, I'm ready to ship. Last check of the release notes, then I'll update the news section in the README and release 0.44!","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632753851, https://github.com/simonw/datasette/issues/838#issuecomment-642993277,https://api.github.com/repos/simonw/datasette/issues/838,642993277,MDEyOklzc3VlQ29tbWVudDY0Mjk5MzI3Nw==,9599,2020-06-12T00:18:26Z,2020-06-12T00:18:50Z,OWNER,"Have you tried this without the `ProxyPassReverse` directive? I'm worried that might be confusing Datasette. This is the test I used to ensure this feature works - it scrapes all of the links on a bunch of different pages. Could it be missing something here? https://github.com/simonw/datasette/blob/647c5ff0f3e8140f40d7f41f0874ce4e1f4df65c/tests/test_html.py#L1233-L1274 ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637395097, https://github.com/simonw/datasette/issues/824#issuecomment-642991513,https://api.github.com/repos/simonw/datasette/issues/824,642991513,MDEyOklzc3VlQ29tbWVudDY0Mjk5MTUxMw==,9599,2020-06-12T00:11:50Z,2020-06-12T00:11:50Z,OWNER,Done: https://github.com/simonw/datasette-auth-tokens and https://pypi.org/project/datasette-auth-tokens/,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635108074, https://github.com/simonw/datasette/issues/833#issuecomment-642958225,https://api.github.com/repos/simonw/datasette/issues/833,642958225,MDEyOklzc3VlQ29tbWVudDY0Mjk1ODIyNQ==,9599,2020-06-11T22:15:32Z,2020-06-11T22:15:32Z,OWNER,https://github.com/simonw/datasette/blob/29c5ff493ad7918b8fc44ea7920b41530e56dd5d/tests/test_permissions.py#L327-L348,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637253789, https://github.com/simonw/datasette/issues/824#issuecomment-642953605,https://api.github.com/repos/simonw/datasette/issues/824,642953605,MDEyOklzc3VlQ29tbWVudDY0Mjk1MzYwNQ==,9599,2020-06-11T22:02:32Z,2020-06-11T22:02:32Z,OWNER,`datasette-auth-tokens` can be the name. I can get a simple initial version of it running pretty quickly.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635108074, https://github.com/simonw/datasette/issues/824#issuecomment-642952962,https://api.github.com/repos/simonw/datasette/issues/824,642952962,MDEyOklzc3VlQ29tbWVudDY0Mjk1Mjk2Mg==,9599,2020-06-11T22:01:58Z,2020-06-11T22:01:58Z,OWNER,"Alternative idea: a plugin that handles Bearer token authentication. Uses `metadata.json` with secret plugin values to map an incoming token to an actor dictionary, which can then be mapped to permissions.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635108074, https://github.com/simonw/datasette/issues/824#issuecomment-642951150,https://api.github.com/repos/simonw/datasette/issues/824,642951150,MDEyOklzc3VlQ29tbWVudDY0Mjk1MTE1MA==,9599,2020-06-11T22:00:17Z,2020-06-11T22:00:17Z,OWNER,"I got this working: https://github.com/simonw/datasette-auth-github/pull/64 Just one problem: it uses the existing `ds_actor` cookie, which means it doesn't actually exercise the `actor_from_request` plugin! It does use `register_routes` though.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635108074, https://github.com/simonw/datasette/issues/220#issuecomment-642944645,https://api.github.com/repos/simonw/datasette/issues/220,642944645,MDEyOklzc3VlQ29tbWVudDY0Mjk0NDY0NQ==,9599,2020-06-11T21:49:55Z,2020-06-11T21:49:55Z,OWNER,"I'm OK with not implementing this - I've got used to the existing mechanism, and it doesn't frustrate me enough to work on this more.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",314847571, https://github.com/simonw/datasette/issues/832#issuecomment-642907021,https://api.github.com/repos/simonw/datasette/issues/832,642907021,MDEyOklzc3VlQ29tbWVudDY0MjkwNzAyMQ==,9599,2020-06-11T20:20:35Z,2020-06-11T20:20:35Z,OWNER,"I think the new `.check_permissions()` should be a documented utility that is available to plugins. Maybe a method on `datasette`?","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636722501, https://github.com/simonw/datasette/issues/832#issuecomment-642906681,https://api.github.com/repos/simonw/datasette/issues/832,642906681,MDEyOklzc3VlQ29tbWVudDY0MjkwNjY4MQ==,9599,2020-06-11T20:19:47Z,2020-06-11T20:20:02Z,OWNER,"So for the following: ``` await self.check_permissions(request, [ (""view-table"", (database, table)), (""view-database"", database), ""view-instance"", ]) ``` The logic is: if the first test returns `True`, you get access. If it returns `False` you are denied. If it says `None` then move on to the next check in the list and repeat.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636722501, https://github.com/simonw/datasette/issues/833#issuecomment-642905424,https://api.github.com/repos/simonw/datasette/issues/833,642905424,MDEyOklzc3VlQ29tbWVudDY0MjkwNTQyNA==,9599,2020-06-11T20:16:41Z,2020-06-11T20:16:41Z,OWNER,I'll add a new test in `test_permissions.py` which locks down an instance and then loops through paths as the anonymous user making sure they aren't accessible.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637253789, https://github.com/simonw/datasette/issues/833#issuecomment-642902208,https://api.github.com/repos/simonw/datasette/issues/833,642902208,MDEyOklzc3VlQ29tbWVudDY0MjkwMjIwOA==,9599,2020-06-11T20:08:57Z,2020-06-11T20:08:57Z,OWNER,"I'm tempted to add a `view-instance` check before routing any URLs, but that wouldn't be compatible with the idea in #832 that having `view-table` should be enough to view a table even if you don't pass `view-instance`.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637253789, https://github.com/simonw/datasette/issues/833#issuecomment-642874724,https://api.github.com/repos/simonw/datasette/issues/833,642874724,MDEyOklzc3VlQ29tbWVudDY0Mjg3NDcyNA==,9599,2020-06-11T19:07:49Z,2020-06-11T19:07:49Z,OWNER,A live demo running the `datasette-auth-github` plugin will help demonstrate this.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",637253789, https://github.com/simonw/datasette/issues/801#issuecomment-642870553,https://api.github.com/repos/simonw/datasette/issues/801,642870553,MDEyOklzc3VlQ29tbWVudDY0Mjg3MDU1Mw==,9599,2020-06-11T18:58:49Z,2020-06-11T18:58:49Z,OWNER,I've implemented this in a plugin instead: https://github.com/simonw/datasette-permissions-sql,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",631932926, https://github.com/simonw/datasette/issues/832#issuecomment-642795966,https://api.github.com/repos/simonw/datasette/issues/832,642795966,MDEyOklzc3VlQ29tbWVudDY0Mjc5NTk2Ng==,9599,2020-06-11T16:37:21Z,2020-06-11T16:37:21Z,OWNER,"How would I document this? Probably in another section on https://datasette.readthedocs.io/en/latest/authentication.html#permissions But I'd also need to add documentation to the individual views stating what permissions are checked and in what order. I could do that on this page: https://datasette.readthedocs.io/en/latest/pages.html","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636722501, https://github.com/simonw/datasette/pull/809#issuecomment-642772344,https://api.github.com/repos/simonw/datasette/issues/809,642772344,MDEyOklzc3VlQ29tbWVudDY0Mjc3MjM0NA==,9599,2020-06-11T16:01:15Z,2020-06-11T16:01:15Z,OWNER,"``` datasette package fixtures.db --secret woot --branch master Sending build context to Docker daemon 260.6kB Step 1/9 : FROM python:3.8 3.8: Pulling from library/python e9afc4f90ab0: Downloading [=======> ] 7.195MB/50.39MB 989e6b19a265: Downloading [============================> ] 4.475MB/7.812MB af14b6c2f878: Downloading [===========================> ] 5.422MB/9.996MB 5573c4b30949: Waiting 11a88e764313: Waiting ee776f0e36af: Waiting 513c90a1afc3: Waiting df9b9e95bdb9: Waiting 86c9edb54464: Waiting ... datasette package fixtures.db --secret woot --branch master docker run -p 8001:8001 a155798bd842 ``` This works too.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632919570, https://github.com/simonw/datasette/pull/809#issuecomment-642754589,https://api.github.com/repos/simonw/datasette/issues/809,642754589,MDEyOklzc3VlQ29tbWVudDY0Mjc1NDU4OQ==,9599,2020-06-11T15:45:25Z,2020-06-11T15:45:25Z,OWNER," datasette publish cloudrun fixtures.db --service datasette-publish-secret --branch=master https://datasette-publish-secret-j7hipcg4aq-uw.a.run.app/-/messages","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632919570, https://github.com/simonw/datasette/pull/809#issuecomment-642750790,https://api.github.com/repos/simonw/datasette/issues/809,642750790,MDEyOklzc3VlQ29tbWVudDY0Mjc1MDc5MA==,9599,2020-06-11T15:42:23Z,2020-06-11T15:42:23Z,OWNER," datasette publish heroku fixtures.db -n datasette-publish-secret --branch=master https://datasette-publish-secret.herokuapp.com/-/messages - Heroku works. ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632919570, https://github.com/simonw/datasette/pull/809#issuecomment-642745518,https://api.github.com/repos/simonw/datasette/issues/809,642745518,MDEyOklzc3VlQ29tbWVudDY0Mjc0NTUxOA==,9599,2020-06-11T15:38:51Z,2020-06-11T15:38:51Z,OWNER,The way to manually test this is to publish a database to each provider and then check that the `/-/messages` debug tool works.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632919570, https://github.com/simonw/datasette/issues/832#issuecomment-642741930,https://api.github.com/repos/simonw/datasette/issues/832,642741930,MDEyOklzc3VlQ29tbWVudDY0Mjc0MTkzMA==,9599,2020-06-11T15:35:53Z,2020-06-11T15:36:05Z,OWNER,"May the fix here is to implement a `.check_permissions()` method which passes when the first permission passes? ```python await self.check_permissions(request, [ (""view-table"", (database, table)), (""view-database"", database), ""view-instance"", ]) ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636722501, https://github.com/simonw/datasette/issues/394#issuecomment-642522285,https://api.github.com/repos/simonw/datasette/issues/394,642522285,MDEyOklzc3VlQ29tbWVudDY0MjUyMjI4NQ==,58298410,2020-06-11T09:15:19Z,2020-06-11T09:15:19Z,NONE,"Hi @wragge, This looks great, thanks for the share! I refactored it into a self-contained function, binding on a random available TCP port (multi-user context). I am using subprocess API directly since the `%run` magic was leaving defunct process behind :/ ![image](https://user-images.githubusercontent.com/58298410/84367566-b5d0d500-abd4-11ea-96e2-f5c05a28e506.png) ```python import socket from signal import SIGINT from subprocess import Popen, PIPE from IPython.display import display, HTML from notebook.notebookapp import list_running_servers def get_free_tcp_port(): """""" Get a free TCP port. """""" tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp.bind(('', 0)) _, port = tcp.getsockname() tcp.close() return port def datasette(database): """""" Run datasette on an SQLite database. """""" # Get current running servers servers = list_running_servers() # Get the current base url base_url = next(servers)['base_url'] # Get a free port port = get_free_tcp_port() # Create a base url for Datasette suing the proxy path proxy_url = f'{base_url}proxy/absolute/{port}/' # Display a link to Datasette display(HTML(f'

View Datasette (Click on the stop button to close the Datasette server)

')) # Launch Datasette with Popen( [ 'python', '-m', 'datasette', '--', database, '--port', str(port), '--config', f'base_url:{proxy_url}' ], stdout=PIPE, stderr=PIPE, bufsize=1, universal_newlines=True ) as p: print(p.stdout.readline(), end='') while True: try: line = p.stderr.readline() if not line: break print(line, end='') exit_code = p.poll() except KeyboardInterrupt: p.send_signal(SIGINT) ``` Ideally, I'd like some extra magic to notify users when they are leaving the closing the notebook tab and make them terminate the running datasette processes. I'll be looking for it.","{""total_count"": 1, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 1, ""rocket"": 0, ""eyes"": 0}",396212021, https://github.com/simonw/datasette/issues/818#issuecomment-642420375,https://api.github.com/repos/simonw/datasette/issues/818,642420375,MDEyOklzc3VlQ29tbWVudDY0MjQyMDM3NQ==,9599,2020-06-11T05:40:07Z,2020-06-11T05:40:07Z,OWNER,https://github.com/simonw/datasette-permissions-sql is now released as a 0.1a here: https://pypi.org/project/datasette-permissions-sql/,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",634917088, https://github.com/simonw/datasette/issues/832#issuecomment-642412017,https://api.github.com/repos/simonw/datasette/issues/832,642412017,MDEyOklzc3VlQ29tbWVudDY0MjQxMjAxNw==,9599,2020-06-11T05:13:59Z,2020-06-11T05:13:59Z,OWNER,"Relevant code: https://github.com/simonw/datasette/blob/ce4958018ede00fbdadf0c37a99889b6901bfb9b/datasette/views/table.py#L267-L272","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636722501, https://github.com/simonw/datasette/issues/831#issuecomment-642324847,https://api.github.com/repos/simonw/datasette/issues/831,642324847,MDEyOklzc3VlQ29tbWVudDY0MjMyNDg0Nw==,9599,2020-06-10T23:50:55Z,2020-06-10T23:50:55Z,OWNER,"Actually I'm not sure about this. If `""allow"": null` means ""no-one can do this"", what's the allow block syntax for ""everyone can do this""? It could be `""allow"": {}` - but that's not intuitive because normally the allow block shows keys that need to match. `{}` suggests to me that no matches are possible. So I think I'm going to stick with the current mechanism, which is that `""allow"": null` means ""anyone can do this"" and `""allow"": {}` means ""no-one can do this"".","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636614868, https://github.com/simonw/datasette/issues/818#issuecomment-642231871,https://api.github.com/repos/simonw/datasette/issues/818,642231871,MDEyOklzc3VlQ29tbWVudDY0MjIzMTg3MQ==,9599,2020-06-10T20:11:50Z,2020-06-10T20:11:50Z,OWNER,"`datasette-permissions-sql` ```yaml plugins: datasette-permissions-sql: view-instance: |- select count(*) from users where admin = 1 and id = :id ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",634917088, https://github.com/simonw/datasette/issues/818#issuecomment-642230499,https://api.github.com/repos/simonw/datasette/issues/818,642230499,MDEyOklzc3VlQ29tbWVudDY0MjIzMDQ5OQ==,9599,2020-06-10T20:08:46Z,2020-06-10T20:09:26Z,OWNER,"What's a simple but useful plugin I could release that exercises this hook? Ideally one which executes permission checks against the database somehow. I could do a simplest-possible implementation of the idea in #801 (allow-by-query).","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",634917088, https://github.com/simonw/datasette/issues/818#issuecomment-642229899,https://api.github.com/repos/simonw/datasette/issues/818,642229899,MDEyOklzc3VlQ29tbWVudDY0MjIyOTg5OQ==,9599,2020-06-10T20:07:36Z,2020-06-10T20:07:36Z,OWNER,"New policy in 9f236c4 dictates that this should be in Milestone 0.44 after all: > * **New plugin hooks** should only be shipped if accompanied by a separate release of a non-demo plugin that uses them.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",634917088, https://github.com/simonw/datasette/issues/829#issuecomment-642217520,https://api.github.com/repos/simonw/datasette/issues/829,642217520,MDEyOklzc3VlQ29tbWVudDY0MjIxNzUyMA==,9599,2020-06-10T19:41:35Z,2020-06-10T19:41:35Z,OWNER,"I didn't bother with the alternative epoch - it only shaves off two or three bytes from the cookie. Documentation for the new `ds_actor` cookie shape is here: https://datasette.readthedocs.io/en/latest/authentication.html#the-ds-actor-cookie","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636426530, https://github.com/simonw/datasette/issues/829#issuecomment-642178604,https://api.github.com/repos/simonw/datasette/issues/829,642178604,MDEyOklzc3VlQ29tbWVudDY0MjE3ODYwNA==,9599,2020-06-10T18:18:36Z,2020-06-10T18:20:19Z,OWNER,"Even shorter: encode an integer that is the difference between that expiry timestamp and a more recent epoch - June 1st 2020 will do. ``` >>> import datetime, calendar >>> calendar.timegm(datetime.date(2020, 6, 1).timetuple()) 1590969600 >>> import baseconv >>> baseconv.base62.encode(int(time.time() - 1590969600)) '3XST' ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636426530, https://github.com/simonw/datasette/issues/829#issuecomment-642176180,https://api.github.com/repos/simonw/datasette/issues/829,642176180,MDEyOklzc3VlQ29tbWVudDY0MjE3NjE4MA==,9599,2020-06-10T18:14:02Z,2020-06-10T18:14:15Z,OWNER,"And the `e` key can be `null`or missing for ""never expires"".","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636426530, https://github.com/simonw/datasette/issues/829#issuecomment-642175892,https://api.github.com/repos/simonw/datasette/issues/829,642175892,MDEyOklzc3VlQ29tbWVudDY0MjE3NTg5Mg==,9599,2020-06-10T18:13:26Z,2020-06-10T18:13:26Z,OWNER,"I'm going with `expires_at` - except to keep the cookies shorter the key will be called `e` and the actor will go in `a`, like this: ```json { ""e"": ""1UuHoo"", ""a"": {""id"": ""root""} } ``` That `e` value is a base64 encoded expiry integer timestamp (again for a shorter cookie) - using https://pypi.org/project/python-baseconv/","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636426530, https://github.com/simonw/datasette/issues/829#issuecomment-642174272,https://api.github.com/repos/simonw/datasette/issues/829,642174272,MDEyOklzc3VlQ29tbWVudDY0MjE3NDI3Mg==,9599,2020-06-10T18:10:13Z,2020-06-10T18:10:13Z,OWNER,"Some options: - Redesign the `ds_actor` cookie to be `{""expires_at"": 1591811250, ""actor"": ...}` - check if it has expired in that default `actor_from_request` hook - Let plugins set an additional cookie of some sort - Expect plugins that care about this to set a cookie with a different name and implement their own `actor_from_request` against that","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636426530, https://github.com/simonw/datasette/issues/829#issuecomment-642161210,https://api.github.com/repos/simonw/datasette/issues/829,642161210,MDEyOklzc3VlQ29tbWVudDY0MjE2MTIxMA==,9599,2020-06-10T17:45:58Z,2020-06-10T17:45:58Z,OWNER,"`itsdangerous` has this ability but you specify the max-age when you call unsign: https://itsdangerous.palletsprojects.com/en/1.1.x/timed/ > s.unsign(string, max_age=5) > Traceback (most recent call last): > ... > itsdangerous.exc.SignatureExpired: Signature age 15 > 5 seconds I currently only decode the `ds_actor` cookie in one place: https://github.com/simonw/datasette/blob/d828abaddec0dce3ec4b4eeddc3a74384e52cf34/datasette/actor_auth_cookie.py#L5-L12 If plugins want to be able to set their own policies on how long the `ds_actor` cookie should remain valid, how do I know to listen to them when decoding the cookie here?","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",636426530, https://github.com/simonw/datasette/issues/394#issuecomment-641908346,https://api.github.com/repos/simonw/datasette/issues/394,641908346,MDEyOklzc3VlQ29tbWVudDY0MTkwODM0Ng==,127565,2020-06-10T10:22:54Z,2020-06-10T10:22:54Z,CONTRIBUTOR,"There's a working demo here: https://github.com/wragge/datasette-test And if you want something that's more than just proof-of-concept, here's a notebook which does some harvesting from web archives and then displays the results using Datasette: https://nbviewer.jupyter.org/github/GLAM-Workbench/web-archives/blob/master/explore_presentations.ipynb","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",396212021, https://github.com/simonw/datasette/issues/394#issuecomment-641889565,https://api.github.com/repos/simonw/datasette/issues/394,641889565,MDEyOklzc3VlQ29tbWVudDY0MTg4OTU2NQ==,58298410,2020-06-10T09:49:34Z,2020-06-10T09:49:34Z,NONE,"Hi, I came across this issue while looking for a way to spawn Datasette as a SQLite files viewer in JupyterLab. I found https://github.com/simonw/jupyterserverproxy-datasette-demo which seems to be the most up to date proof of concept, but it seems to be failing to list the available db (at least in the Binder demo, https://hub.gke.mybinder.org/user/simonw-jupyters--datasette-demo-uw4dmlnn/datasette/, I only have `:memory`). Does anyone tried to improve on this proof of concept to have a Datasette visualization for SQLite files? Thanks!","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",396212021, https://github.com/simonw/datasette/issues/828#issuecomment-641713087,https://api.github.com/repos/simonw/datasette/issues/828,641713087,MDEyOklzc3VlQ29tbWVudDY0MTcxMzA4Nw==,9599,2020-06-10T04:28:17Z,2020-06-10T04:28:17Z,OWNER,"Fixed. https://datasette.readthedocs.io/en/latest/changelog.html ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635914822, https://github.com/simonw/datasette/issues/828#issuecomment-641710745,https://api.github.com/repos/simonw/datasette/issues/828,641710745,MDEyOklzc3VlQ29tbWVudDY0MTcxMDc0NQ==,9599,2020-06-10T04:19:31Z,2020-06-10T04:19:31Z,OWNER,https://docs.readthedocs.io/en/stable/guides/adding-custom-css.html,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635914822, https://github.com/simonw/datasette/issues/828#issuecomment-641710670,https://api.github.com/repos/simonw/datasette/issues/828,641710670,MDEyOklzc3VlQ29tbWVudDY0MTcxMDY3MA==,9599,2020-06-10T04:19:17Z,2020-06-10T04:19:17Z,OWNER,"This CSS seems to fix it: ```css a.external {overflow-wrap: anywhere;} ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635914822, https://github.com/simonw/datasette/issues/806#issuecomment-641637696,https://api.github.com/repos/simonw/datasette/issues/806,641637696,MDEyOklzc3VlQ29tbWVudDY0MTYzNzY5Ng==,9599,2020-06-09T23:46:00Z,2020-06-09T23:46:00Z,OWNER,"The issues that should be referenced from this release are: #395, #519, #576, #699, #706, #774, #777, #781, #784, #788, #790, #797, #798, #800, #802, #804, #819, #822 ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632753851, https://github.com/simonw/datasette/issues/806#issuecomment-641634749,https://api.github.com/repos/simonw/datasette/issues/806,641634749,MDEyOklzc3VlQ29tbWVudDY0MTYzNDc0OQ==,9599,2020-06-09T23:34:52Z,2020-06-09T23:34:52Z,OWNER,Preview of the release notes is now available here: https://datasette.readthedocs.io/en/latest/changelog.html#v0-44,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632753851, https://github.com/simonw/datasette/issues/795#issuecomment-641616185,https://api.github.com/repos/simonw/datasette/issues/795,641616185,MDEyOklzc3VlQ29tbWVudDY0MTYxNjE4NQ==,9599,2020-06-09T22:33:33Z,2020-06-09T22:33:33Z,OWNER,Documentation: https://datasette.readthedocs.io/en/latest/internals.html#setting-cookies-with-response-set-cookie,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",629541395, https://github.com/simonw/datasette/issues/826#issuecomment-641616060,https://api.github.com/repos/simonw/datasette/issues/826,641616060,MDEyOklzc3VlQ29tbWVudDY0MTYxNjA2MA==,9599,2020-06-09T22:33:12Z,2020-06-09T22:33:12Z,OWNER,https://datasette.readthedocs.io/en/latest/authentication.html#the-ds-actor-cookie,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635519358, https://github.com/simonw/datasette/issues/806#issuecomment-641604210,https://api.github.com/repos/simonw/datasette/issues/806,641604210,MDEyOklzc3VlQ29tbWVudDY0MTYwNDIxMA==,9599,2020-06-09T21:59:33Z,2020-06-09T22:00:11Z,OWNER,"AWS IAM uses action and resource terminology: https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction_access-management.html - I think that's where I got that language: > ```json > { > ""Version"": ""2012-10-17"", > ""Statement"": { > ""Effect"": ""Allow"", > ""Action"": ""dynamodb:*"", > ""Resource"": ""arn:aws:dynamodb:us-east-2:123456789012:table/Books"" > } > } > ``` I'm going to stick with ""action"" in its current meaning.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632753851, https://github.com/simonw/datasette/issues/806#issuecomment-641603457,https://api.github.com/repos/simonw/datasette/issues/806,641603457,MDEyOklzc3VlQ29tbWVudDY0MTYwMzQ1Nw==,9599,2020-06-09T21:57:32Z,2020-06-09T21:57:32Z,OWNER,"operation, procedure, process as alternative words for those menu items?","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632753851, https://github.com/simonw/datasette/issues/806#issuecomment-641602794,https://api.github.com/repos/simonw/datasette/issues/806,641602794,MDEyOklzc3VlQ29tbWVudDY0MTYwMjc5NA==,9599,2020-06-09T21:55:45Z,2020-06-09T21:55:45Z,OWNER,"Last-minute thought: Should I worry about calling permissions ""actions"", when I have an idea for a future plugin hook that allows plugins to add something I was going to call ""actions"" to database, table and row pages? Those actions would take the form of menu item commands that Do Something to the selected object. If I use ""actions"" to mean permission names, will I be able to find a good alternative name for these dynamic menu items?","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632753851, https://github.com/simonw/datasette/issues/804#issuecomment-641538982,https://api.github.com/repos/simonw/datasette/issues/804,641538982,MDEyOklzc3VlQ29tbWVudDY0MTUzODk4Mg==,9599,2020-06-09T20:01:30Z,2020-06-09T20:01:30Z,OWNER,Now fully documented here: https://datasette.readthedocs.io/en/latest/contributing.html#setting-up-a-development-environment,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632673972, https://github.com/simonw/datasette/issues/804#issuecomment-641538799,https://api.github.com/repos/simonw/datasette/issues/804,641538799,MDEyOklzc3VlQ29tbWVudDY0MTUzODc5OQ==,9599,2020-06-09T20:01:08Z,2020-06-09T20:01:08Z,OWNER," $ python tests/fixtures.py fixtures.db fixtures-metadata.json fixtures-plugins Test tables written to fixtures.db - metadata written to fixtures-metadata.json Wrote plugin: fixtures-plugins/register_output_renderer.py Wrote plugin: fixtures-plugins/view_name.py Wrote plugin: fixtures-plugins/my_plugin.py Wrote plugin: fixtures-plugins/messages_output_renderer.py Wrote plugin: fixtures-plugins/my_plugin_2.py","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632673972, https://github.com/simonw/datasette/issues/804#issuecomment-641528737,https://api.github.com/repos/simonw/datasette/issues/804,641528737,MDEyOklzc3VlQ29tbWVudDY0MTUyODczNw==,9599,2020-06-09T19:39:24Z,2020-06-09T19:39:24Z,OWNER,Switched to 0.44 milestone because I don't like shipping releases with known bugs.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632673972, https://github.com/simonw/datasette/issues/827#issuecomment-641528269,https://api.github.com/repos/simonw/datasette/issues/827,641528269,MDEyOklzc3VlQ29tbWVudDY0MTUyODI2OQ==,9599,2020-06-09T19:38:30Z,2020-06-09T19:38:30Z,OWNER,https://datasette.readthedocs.io/en/latest/internals.html#csrf-protection,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635696400, https://github.com/simonw/datasette/issues/825#issuecomment-641406944,https://api.github.com/repos/simonw/datasette/issues/825,641406944,MDEyOklzc3VlQ29tbWVudDY0MTQwNjk0NA==,9599,2020-06-09T16:12:02Z,2020-06-09T17:19:19Z,OWNER,"Alternative design: leave actor alone. Instead specify that allow blocks can look like this: ```json { ""allow"": { ""unauthenticated"": true } } ``` I like this: the above block is very self-documenting. The `""id"": ""*""` mechanism means there is already precedent for allow keys with special meaning. **I'm going with this design.**","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635147716, https://github.com/simonw/datasette/issues/825#issuecomment-641452563,https://api.github.com/repos/simonw/datasette/issues/825,641452563,MDEyOklzc3VlQ29tbWVudDY0MTQ1MjU2Mw==,9599,2020-06-09T17:08:00Z,2020-06-09T17:08:00Z,OWNER,https://datasette.readthedocs.io/en/latest/authentication.html#defining-permissions-with-allow-blocks,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635147716, https://github.com/simonw/datasette/issues/825#issuecomment-641449725,https://api.github.com/repos/simonw/datasette/issues/825,641449725,MDEyOklzc3VlQ29tbWVudDY0MTQ0OTcyNQ==,9599,2020-06-09T17:02:31Z,2020-06-09T17:02:31Z,OWNER,Documented at the bottom of this section: https://github.com/simonw/datasette/blob/7633b9ab249b2dce5ee0b4fcf9542c13a1703ef0/docs/authentication.rst#defining-permissions-with-allow-blocks,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635147716, https://github.com/simonw/datasette/issues/825#issuecomment-641412424,https://api.github.com/repos/simonw/datasette/issues/825,641412424,MDEyOklzc3VlQ29tbWVudDY0MTQxMjQyNA==,9599,2020-06-09T16:22:07Z,2020-06-09T16:22:07Z,OWNER,"When I implement this I should also document default allow vs default deny as a concept, and specify that default next to every documented permission.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635147716, https://github.com/simonw/datasette/issues/795#issuecomment-641361311,https://api.github.com/repos/simonw/datasette/issues/795,641361311,MDEyOklzc3VlQ29tbWVudDY0MTM2MTMxMQ==,9599,2020-06-09T15:11:50Z,2020-06-09T15:11:50Z,OWNER,Also: https://github.com/simonw/datasette/blob/dfff34e1987976e72f58ee7b274952840b1f4b71/datasette/views/special.py#L63-L76,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",629541395, https://github.com/simonw/datasette/issues/826#issuecomment-641360187,https://api.github.com/repos/simonw/datasette/issues/826,641360187,MDEyOklzc3VlQ29tbWVudDY0MTM2MDE4Nw==,9599,2020-06-09T15:10:00Z,2020-06-09T15:11:24Z,OWNER,Also a good reminder that I need a `set_cookie()` function (#795) so I don't have to mess around with `SimpleCookie` directly.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635519358, https://github.com/simonw/datasette/issues/826#issuecomment-641359103,https://api.github.com/repos/simonw/datasette/issues/826,641359103,MDEyOklzc3VlQ29tbWVudDY0MTM1OTEwMw==,9599,2020-06-09T15:08:07Z,2020-06-09T15:10:33Z,OWNER,"I should probably add a utility function for setting that cookie - right now the only code that does that is here: https://github.com/simonw/datasette/blob/dfff34e1987976e72f58ee7b274952840b1f4b71/datasette/views/special.py#L63-L76","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635519358, https://github.com/simonw/datasette/issues/812#issuecomment-641353729,https://api.github.com/repos/simonw/datasette/issues/812,641353729,MDEyOklzc3VlQ29tbWVudDY0MTM1MzcyOQ==,9599,2020-06-09T14:59:25Z,2020-06-09T14:59:25Z,OWNER,I'm going to figure this out by working with https://github.com/simonw/datasette-auth-github/issues/62,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",634112607, https://github.com/simonw/datasette/issues/823#issuecomment-641353186,https://api.github.com/repos/simonw/datasette/issues/823,641353186,MDEyOklzc3VlQ29tbWVudDY0MTM1MzE4Ng==,9599,2020-06-09T14:58:36Z,2020-06-09T14:58:36Z,OWNER,"Docs now say: > The actor dictionary can be any shape - the design of that data structure is left up to the plugins. A useful convention is to include an `""id""` string, as demonstrated by the ""root"" actor below.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635107393, https://github.com/simonw/datasette/issues/825#issuecomment-641320947,https://api.github.com/repos/simonw/datasette/issues/825,641320947,MDEyOklzc3VlQ29tbWVudDY0MTMyMDk0Nw==,9599,2020-06-09T14:06:46Z,2020-06-09T14:06:46Z,OWNER,"I'm torn between `anonymous` and `anon` - because the latter is less typing, and I envisage people writing a lot of code like this: ```python if actor.get(""anonymous""): # ... ``` I'm going with `anonymous` because it's that tiny bit clearer than `anon`.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635147716, https://github.com/simonw/datasette/issues/825#issuecomment-641062164,https://api.github.com/repos/simonw/datasette/issues/825,641062164,MDEyOklzc3VlQ29tbWVudDY0MTA2MjE2NA==,9599,2020-06-09T06:30:24Z,2020-06-09T14:05:33Z,OWNER,"Idea: the anonymous actor could be passed to `actor_matches_allow()` as: ```json {""anonymous"": true} ``` Then allow blocks like this could be used to allow them: ```json { ""plugins"": { ""datasette-upload-csvs"": { ""allow"": { ""anonymous"": true } } } } ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635147716, https://github.com/simonw/datasette/issues/823#issuecomment-641059221,https://api.github.com/repos/simonw/datasette/issues/823,641059221,MDEyOklzc3VlQ29tbWVudDY0MTA1OTIyMQ==,9599,2020-06-09T06:23:51Z,2020-06-09T06:24:09Z,OWNER,"I don't like the ""id"" requirement. I can think of plenty of situations where a unique ID might not be available: - auth against an external token - an email address or a phone number for example - auth using encrypted tokens - where decrypting the token tells you exactly what permissions that token should have, like in https://blog.thea.codes/building-a-stateless-api-proxy/","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635107393, https://github.com/simonw/datasette/issues/806#issuecomment-641026726,https://api.github.com/repos/simonw/datasette/issues/806,641026726,MDEyOklzc3VlQ29tbWVudDY0MTAyNjcyNg==,9599,2020-06-09T04:52:07Z,2020-06-09T04:52:07Z,OWNER,Changelog for this is going to be huge - 96 commits since 0.43 already! https://github.com/simonw/datasette/compare/0.43...master,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632753851, https://github.com/simonw/datasette/issues/818#issuecomment-641026230,https://api.github.com/repos/simonw/datasette/issues/818,641026230,MDEyOklzc3VlQ29tbWVudDY0MTAyNjIzMA==,9599,2020-06-09T04:50:24Z,2020-06-09T04:50:24Z,OWNER,I'm dropping this from the 0.44 milestone.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",634917088, https://github.com/simonw/datasette/issues/823#issuecomment-641025760,https://api.github.com/repos/simonw/datasette/issues/823,641025760,MDEyOklzc3VlQ29tbWVudDY0MTAyNTc2MA==,9599,2020-06-09T04:48:40Z,2020-06-09T04:48:40Z,OWNER,"I should assert that `""id""` exists and is a string in the code that calls the `actor_from_request` hook.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635107393, https://github.com/simonw/datasette/issues/805#issuecomment-641017851,https://api.github.com/repos/simonw/datasette/issues/805,641017851,MDEyOklzc3VlQ29tbWVudDY0MTAxNzg1MQ==,9599,2020-06-09T04:17:00Z,2020-06-09T04:17:00Z,OWNER,I can't get Datasette working on Glitch installed from a URL - I'm going to try this on Glitch once I've shipped the 0.44 release in #806.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632724154, https://github.com/simonw/datasette/issues/805#issuecomment-641017721,https://api.github.com/repos/simonw/datasette/issues/805,641017721,MDEyOklzc3VlQ29tbWVudDY0MTAxNzcyMQ==,9599,2020-06-09T04:16:28Z,2020-06-09T04:16:28Z,OWNER,"Create `data.db` with: ``` echo '{""emoji"": ""🐯"", ""score"": 0}' | sqlite-utils insert data.db emojis --pk=emoji - echo '{""emoji"": ""🐺"", ""score"": 0}' | sqlite-utils insert data.db emojis --pk=emoji - ``` Then run Datasette with this `metadata.yaml`: ```yaml title: Datasette Poll databases: data: queries: vote: sql: |- update emojis set score = score + 1 where emoji = :emoji write: true ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",632724154, https://github.com/simonw/datasette/issues/797#issuecomment-638301073,https://api.github.com/repos/simonw/datasette/issues/797,638301073,MDEyOklzc3VlQ29tbWVudDYzODMwMTA3Mw==,9599,2020-06-03T16:14:54Z,2020-06-09T04:00:40Z,OWNER,I want a unit test that exercises this for both writable and regular canned queries.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",630120235, https://github.com/simonw/datasette/issues/818#issuecomment-641013524,https://api.github.com/repos/simonw/datasette/issues/818,641013524,MDEyOklzc3VlQ29tbWVudDY0MTAxMzUyNA==,9599,2020-06-09T03:57:38Z,2020-06-09T04:00:24Z,OWNER,"Problem with that is it's more of a `actor_from_request` opportunity than `permission_allowed`. You could use `actor_from_request` to authenticate API clients from their `Authorization:` header, then use the regular `""allow""` blocks in `metadata.json` to actually assign their permissions. The most interesting permissions plugin would be one that implements permissions against some kind of database schema, hence allowing admins to edit permissions through writable canned queries.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",634917088, https://github.com/simonw/datasette/issues/818#issuecomment-641009744,https://api.github.com/repos/simonw/datasette/issues/818,641009744,MDEyOklzc3VlQ29tbWVudDY0MTAwOTc0NA==,9599,2020-06-09T03:43:18Z,2020-06-09T03:43:18Z,OWNER,`datasette-auth-bearer` perhaps?,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",634917088, https://github.com/simonw/datasette/issues/818#issuecomment-641009442,https://api.github.com/repos/simonw/datasette/issues/818,641009442,MDEyOklzc3VlQ29tbWVudDY0MTAwOTQ0Mg==,9599,2020-06-09T03:41:55Z,2020-06-09T03:41:55Z,OWNER,I want to build a plugin that does `Authorization: Bearer xxx` API key authentication.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",634917088, https://github.com/simonw/datasette/issues/822#issuecomment-641003291,https://api.github.com/repos/simonw/datasette/issues/822,641003291,MDEyOklzc3VlQ29tbWVudDY0MTAwMzI5MQ==,9599,2020-06-09T03:17:43Z,2020-06-09T03:17:43Z,OWNER,I'm leaning towards `request.url_vars`.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635077656, https://github.com/simonw/datasette/issues/822#issuecomment-641003237,https://api.github.com/repos/simonw/datasette/issues/822,641003237,MDEyOklzc3VlQ29tbWVudDY0MTAwMzIzNw==,9599,2020-06-09T03:17:32Z,2020-06-09T03:17:32Z,OWNER,Currently querystring parameters are accessed through `request.args` and POST variables through `request.post_vars()`. Would be good to have a name that was somewhat consistent with those.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635077656, https://github.com/simonw/datasette/issues/215#issuecomment-641002504,https://api.github.com/repos/simonw/datasette/issues/215,641002504,MDEyOklzc3VlQ29tbWVudDY0MTAwMjUwNA==,9599,2020-06-09T03:14:32Z,2020-06-09T03:14:32Z,OWNER,Documentation: https://datasette.readthedocs.io/en/latest/plugins.html#register-routes,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",314506669, https://github.com/simonw/datasette/issues/820#issuecomment-640982533,https://api.github.com/repos/simonw/datasette/issues/820,640982533,MDEyOklzc3VlQ29tbWVudDY0MDk4MjUzMw==,9599,2020-06-09T02:00:21Z,2020-06-09T02:00:21Z,OWNER,In the case of registering API tokens it would be useful if the plugin could call a writable canned query which knows how to insert a randomly generated value. This could be achieved using a custom SQL function.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",635049296, https://github.com/simonw/datasette/issues/215#issuecomment-640972952,https://api.github.com/repos/simonw/datasette/issues/215,640972952,MDEyOklzc3VlQ29tbWVudDY0MDk3Mjk1Mg==,9599,2020-06-09T01:24:52Z,2020-06-09T01:25:33Z,OWNER,WIP documentation: https://github.com/simonw/datasette/blob/770dedb21adfc706592e6b5cdf5e751a8720fdf9/docs/plugins.rst#register_routes,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",314506669, https://github.com/simonw/datasette/issues/215#issuecomment-640971470,https://api.github.com/repos/simonw/datasette/issues/215,640971470,MDEyOklzc3VlQ29tbWVudDY0MDk3MTQ3MA==,9599,2020-06-09T01:19:44Z,2020-06-09T01:19:44Z,OWNER,I'll need to add documentation of the `Response` object (and `Response.html()` and `Response.text()` class methods - I should add `Response.json()` too) to the internals page https://datasette.readthedocs.io/en/stable/internals.html,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",314506669, https://github.com/simonw/datasette/issues/215#issuecomment-640960667,https://api.github.com/repos/simonw/datasette/issues/215,640960667,MDEyOklzc3VlQ29tbWVudDY0MDk2MDY2Nw==,9599,2020-06-09T00:41:35Z,2020-06-09T00:41:35Z,OWNER,I'm going to implement this one documentation-first in a pull request.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",314506669,