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/647#issuecomment-1061282743,https://api.github.com/repos/simonw/datasette/issues/647,1061282743,IC_kwDOBm6k_c4_QeO3,9599,2022-03-08T00:32:34Z,2022-03-08T00:32:47Z,OWNER,It would be neat if the plugin could spot old-style hyphen hash URLs (maybe on 404) and redirect those too.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",531755959,
https://github.com/simonw/datasette/issues/647#issuecomment-1061276646,https://api.github.com/repos/simonw/datasette/issues/647,1061276646,IC_kwDOBm6k_c4_Qcvm,9599,2022-03-08T00:22:11Z,2022-03-08T00:22:11Z,OWNER,I'm now convinced this is feasible enough that it's worth doing in time for Datasette 1.0.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",531755959,
https://github.com/simonw/datasette/issues/647#issuecomment-1061276399,https://api.github.com/repos/simonw/datasette/issues/647,1061276399,IC_kwDOBm6k_c4_Qcrv,9599,2022-03-08T00:21:47Z,2022-03-08T00:21:47Z,OWNER,"This seems to do the job:
```python
@hookimpl
def startup(datasette):
for name, database in datasette.databases.items():
if database.hash:
new_name = ""{}_{}"".format(name, database.hash[:7])
del datasette.databases[name]
datasette.databases[new_name] = database
```
Would have to teach the rest of the plugin to split on `_` and to only redirect if the user seems to be hitting the URL for an old hash after which Datasette has been restarted with an updated database.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",531755959,
https://github.com/simonw/datasette/issues/647#issuecomment-1061272544,https://api.github.com/repos/simonw/datasette/issues/647,1061272544,IC_kwDOBm6k_c4_Qbvg,9599,2022-03-08T00:14:42Z,2022-03-08T00:14:42Z,OWNER,Maybe the plugin should interfere with `datasette.databases` on startup and change the registered name for each one?,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",531755959,
https://github.com/simonw/datasette/issues/647#issuecomment-1061267615,https://api.github.com/repos/simonw/datasette/issues/647,1061267615,IC_kwDOBm6k_c4_Qaif,9599,2022-03-08T00:05:43Z,2022-03-08T00:05:43Z,OWNER,"Built a prototype of that plugin:
```python
from datasette import hookimpl
from functools import wraps
@hookimpl
def asgi_wrapper(datasette):
def wrap_with_hashed_urls(app):
@wraps(app)
async def hashed_urls(scope, receive, send):
# Only triggers on pages with a path not starting in /-/
# and where the first page component matches a database name
if scope.get(""type"") != ""http"":
await app(scope, receive, send)
return
path = scope[""path""].lstrip(""/"")
if not path or path.startswith(""-/""):
await app(scope, receive, send)
return
potential_database = path.split(""/"")[0]
# It may or may not be already dbname~hash
if ""~"" in potential_database:
db_name, hash = potential_database.split(""~"", 1)
else:
db_name = potential_database
hash = """"
# Is db_name a database we have a hash for?
try:
db = datasette.get_database(db_name)
except KeyError:
await app(scope, receive, send)
return
if db.hash is not None:
# TODO: make sure db.hash is documented
if db.hash[:7] != hash:
# Send a redirect
path_bits = path.split(""/"")
new_path = ""/"" + ""/"".join([""{}-{}"".format(db_name, db.hash[:7])] + path_bits[1:])
if scope.get(""query_string""):
new_path += ""?"" + scope[""query_string""].decode(""latin-1"")
await send({
""type"": ""http.response.start"",
""status"": 302,
""headers"": [
[b""location"", new_path.encode(""latin1"")]
],
})
await send({""type"": ""http.response.body"", ""body"": b""""})
return
else:
# Add a far-future cache header
async def wrapped_send(event):
if event[""type""] == ""http.response.start"":
original_headers = event.get(""headers"") or []
event = {
""type"": event[""type""],
""status"": event[""status""],
""headers"": original_headers + [
[b""Cache-Control"", b""max-age=31536000""]
],
}
await send(event)
await app(scope, receive, wrapped_send)
return
await app(scope, receive, send)
return hashed_urls
return wrap_with_hashed_urls
```
One catch: it doesn't affect the way URLs are generated - so every internal link within Datasette links to the non-hash version and then triggers a 302 redirect to the hashed version.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",531755959,