{"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1347646516", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1347646516, "node_id": "IC_kwDOBm6k_c5QU3Q0", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T02:07:50Z", "updated_at": "2022-12-13T02:07:50Z", "author_association": "OWNER", "body": "Documentation for the new hook: https://docs.datasette.io/en/latest/plugin_hooks.html#register-permissions-datasette", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1345691103", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1345691103, "node_id": "IC_kwDOBm6k_c5QNZ3f", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-11T23:37:49Z", "updated_at": "2022-12-11T23:37:49Z", "author_association": "OWNER", "body": "Idea: a `/-/permissions` introspection endpoint for listing registered permissions\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343872168", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343872168, "node_id": "IC_kwDOBm6k_c5QGdyo", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T05:29:53Z", "updated_at": "2022-12-09T05:29:53Z", "author_association": "OWNER", "body": "I'm going to address those ideas for changes to the `permission_allowed()` in a separate issue.\r\n\r\nWhat would it take for the `register_permissions()` hook to be something I'm comfortable landing?\r\n\r\nI think it's mainly that the list of permissions it provides should Do More Stuff:\r\n\r\n- Participate in unit tests, in particular this one:\r\n \r\n https://github.com/simonw/datasette/blob/e539c1c024bc62d88df91d9107cbe37e7f0fe55f/tests/conftest.py#L79-L102\r\n\r\n- That new `default` option should be respected - maybe if you omit `default=` from a call to `permission_allowed()` it could fall back on the default from there?\r\n- Log a warning if you attempt to check a permission that wasn't registered\r\n\r\nThen I can use the permissions - in particular their metadata - to help implement his:\r\n\r\n- #1636", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343858998", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343858998, "node_id": "IC_kwDOBm6k_c5QGak2", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T05:12:17Z", "updated_at": "2022-12-09T05:12:17Z", "author_association": "OWNER", "body": "Draft docs for the new plugin hook: https://datasette--1940.org.readthedocs.build/en/1940/plugin_hooks.html#register-permissions-datasette", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343856781", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343856781, "node_id": "IC_kwDOBm6k_c5QGaCN", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T05:10:00Z", "updated_at": "2022-12-09T05:10:00Z", "author_association": "OWNER", "body": "Made a draft PR so ReadTheDocs would deploy my new documentation somewhere.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343844555", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343844555, "node_id": "IC_kwDOBm6k_c5QGXDL", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T04:48:28Z", "updated_at": "2022-12-09T04:48:28Z", "author_association": "OWNER", "body": "I'm going to try a spike in a branch with `datasette.action_allowed(...)` and a `register_permissions()` plugin hook, to see what they look like.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343844112", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343844112, "node_id": "IC_kwDOBm6k_c5QGW8Q", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T04:47:28Z", "updated_at": "2022-12-09T04:47:28Z", "author_association": "OWNER", "body": "I think `action_allowed` is my favourite, even though there's a little bit of concept overlap with `table_actions` and `database_actions`.\r\n\r\nI never really liked those plugin hook names much to be honest, especially since they are inconsistent with `menu_links`:\r\n\r\nhttps://github.com/simonw/datasette/blob/d67f812b7327c7075732688f3df728807503dc58/datasette/hookspecs.py#L123-L135", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343843352", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343843352, "node_id": "IC_kwDOBm6k_c5QGWwY", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T04:45:50Z", "updated_at": "2022-12-09T04:45:50Z", "author_association": "OWNER", "body": "Another option:\r\n\r\n```python\r\nif await datasette.actor_can(actor, \"insert-data\"...)\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343842362", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343842362, "node_id": "IC_kwDOBm6k_c5QGWg6", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T04:43:38Z", "updated_at": "2022-12-09T04:43:38Z", "author_association": "OWNER", "body": "Asked ChatGPT for some alternative names, I didn't like any of them:\r\n\r\n is_permission_granted\r\n has_permission\r\n check_permission\r\n is_action_allowed\r\n check_access_permission\r\n permission_check\r\n validate_permission\r\n check_actor_permission\r\n verify_permission\r\n check_authorization\r\n\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343753386", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343753386, "node_id": "IC_kwDOBm6k_c5QGAyq", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T02:20:20Z", "updated_at": "2022-12-09T02:21:01Z", "author_association": "OWNER", "body": "It's also referenced in this plugin hook:\r\n```python\r\n@hookspec\r\ndef permission_allowed(datasette, actor, action, resource):\r\n \"\"\"Check if actor is allowed to perform this action - return True, False or None\"\"\"\r\n```\r\nBut more importantly, in these ones:\r\n```python\r\n@hookspec\r\ndef table_actions(datasette, actor, database, table, request):\r\n \"\"\"Links for the table actions menu\"\"\"\r\n\r\n\r\n@hookspec\r\ndef database_actions(datasette, actor, database, request):\r\n \"\"\"Links for the database actions menu\"\"\"\r\n```\r\nSo the word \"action\" is already used within Datasette to refer to those things - which are _almost_ but not quite the same as actions-as-permissions: many of the things that show up in those menus relate to permissions the user has, but not necessarily all of them.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343751860", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343751860, "node_id": "IC_kwDOBm6k_c5QGAa0", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T02:18:11Z", "updated_at": "2022-12-09T02:19:23Z", "author_association": "OWNER", "body": "Should I rename \"permission\" to \"action\" elsewhere too? Maybe have a `register_actions(...)` plugin hook instead of adding `register_permissions(...)`? \r\n\r\nWhat else could the word \"action\" mean?\r\n\r\nCurrently it's used in the codebase to refer to GitHub Actions, and for code like this:\r\n```python\r\n if await self.permission_allowed(\r\n actor=actor, action=\"view-instance\", default=True\r\n ):\r\n```\r\nWhich is already revealing the confusion between \"permission\" and \"action\".", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343751261", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343751261, "node_id": "IC_kwDOBm6k_c5QGARd", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T02:17:14Z", "updated_at": "2022-12-09T02:17:14Z", "author_association": "OWNER", "body": "One option:\r\n```python\r\nasync def action_allowed(self, actor, action, database=None, resource=None):\r\n```\r\n`action_allowed` fixes the `permission` v.s. `action` thing a bit, and is a new name that doesn't clash with the existing method. I dropped `default` because that's now a property of the permission itself. `table` is now called `resource` and `database` is a separate parameter.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343749617", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343749617, "node_id": "IC_kwDOBm6k_c5QF_3x", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T02:15:54Z", "updated_at": "2022-12-09T02:15:54Z", "author_association": "OWNER", "body": "What if I came up with a new method name for this, which could co-exist with the old one while that old one was deprecated?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343744338", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343744338, "node_id": "IC_kwDOBm6k_c5QF-lS", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T02:08:42Z", "updated_at": "2022-12-09T02:08:42Z", "author_association": "OWNER", "body": "Extracted a TIL: https://til.simonwillison.net/github/github-code-search-api-uses", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343734812", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343734812, "node_id": "IC_kwDOBm6k_c5QF8Qc", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T01:57:07Z", "updated_at": "2022-12-09T01:57:07Z", "author_association": "OWNER", "body": "This search is better:\r\n\r\n datasette permission_allowed -user:simonw -path:datasette/** -path:docs/** -path:tests/** language:python\r\n\r\nThat returns 11 results: https://cs.github.com/?scopeName=All+repos&scope=&q=datasette+permission_allowed+-user%3Asimonw+-path%3Adatasette%2F**+-path%3Adocs%2F**+-path%3Atests%2F**+language%3Apython\r\n\r\n3 are forks of my repos. The rest are all by four users:\r\n\r\n- [20after4/ddd](https://github.com/20after4/ddd)\r\n- [emg110/datasette-graphql](https://github.com/emg110/datasette-graphql)\r\n- [next-LI/datasette-csv-importer](https://github.com/next-LI/datasette-csv-importer)\r\n- [next-LI/datasette-demo](https://github.com/next-LI/datasette-demo)\r\n- [next-LI/datasette-live-config](https://github.com/next-LI/datasette-live-config)\r\n- [next-LI/datasette-live-permissions](https://github.com/next-LI/datasette-live-permissions)\r\n- [next-LI/datasette-search-all](https://github.com/next-LI/datasette-search-all)\r\n- [next-LI/datasette-surveys](https://github.com/next-LI/datasette-surveys)\r\n- [next-LI/datasette-write](https://github.com/next-LI/datasette-write)\r\n- [rclement/datasette-dashboards](https://github.com/rclement/datasette-dashboards)\r\n\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343728929", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343728929, "node_id": "IC_kwDOBm6k_c5QF60h", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T01:48:11Z", "updated_at": "2022-12-09T01:52:33Z", "author_association": "OWNER", "body": "This code search shows a bunch of repos I don't know about that would be affected by this change: https://cs.github.com/?scopeName=All+repos&scope=&q=datasette+permission_allowed+-user%3Asimonw#\r\n\r\nThese (and likely more):\r\n\r\nRepositories\r\n\r\n- [20after4/ddd](https://github.com/20after4/ddd)\r\n- [next-LI/datasette-csv-importer](https://github.com/next-LI/datasette-csv-importer)\r\n- [digital-land/datasette](https://github.com/digital-land/datasette)\r\n- [mroswell/datasette](https://github.com/mroswell/datasette)\r\n- [next-LI/datasette-live-config](https://github.com/next-LI/datasette-live-config)\r\n- [keladhruv/datasette](https://github.com/keladhruv/datasette)\r\n- [RhetTbull/datasette](https://github.com/RhetTbull/datasette)\r\n- [chriswedgwood/datasette](https://github.com/chriswedgwood/datasette)\r\n- [boan-anbo/datasette](https://github.com/boan-anbo/datasette)\r\n- [MattTriano/datasette](https://github.com/MattTriano/datasette)\r\n- [incadenza/datasette](https://github.com/incadenza/datasette)\r\n- [robdyke/datasette](https://github.com/robdyke/datasette)\r\n- [ctb/datasette](https://github.com/ctb/datasette)\r\n- [eyeseast/datasette](https://github.com/eyeseast/datasette)\r\n- [symbol-management/api-match-audit](https://github.com/symbol-management/api-match-audit)\r\n\r\nActually a lot of those are forks of Datasette itself - so maybe this is manageable?\r\n\r\nWould be nice if I could come up with a GitHub search that excluded any repos with \"datasette\" as their exact name.\r\n\r\nhttps://docs.github.com/en/search-github/github-code-search/understanding-github-code-search-syntax#using-qualifiers says:\r\n\r\n> **Note:** The new code search beta does not currently support regular expressions or partial matching for repository names, so you will have to type the entire repository name (including the user prefix) for the `repo:` qualifier to work.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343727184", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343727184, "node_id": "IC_kwDOBm6k_c5QF6ZQ", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T01:45:15Z", "updated_at": "2022-12-09T01:45:15Z", "author_association": "OWNER", "body": "Moving the concept of the default for the permission into this registry warrants a redesign of this method anyway:\r\n\r\nhttps://github.com/simonw/datasette/blob/e539c1c024bc62d88df91d9107cbe37e7f0fe55f/datasette/app.py#L706", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343724732", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343724732, "node_id": "IC_kwDOBm6k_c5QF5y8", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T01:40:44Z", "updated_at": "2022-12-09T01:43:25Z", "author_association": "OWNER", "body": "```python\r\nPermission = collections.namedtuple( \r\n \"Permission\", (\"name\", \"abbr\", \"takes_database\", \"takes_table\", \"default\") \r\n) \r\n```\r\nI don`t think that design is quite right.\r\n\r\n- Elsewhere in the code the concept is called an \"action\" rather than a \"permission\" - I think I can stick with the `Permission` name here though, it's pretty clear\r\n- `takes_database` - is `takes_` the right verb here?\r\n- `takes_table` can also refer to a SQL view or a canned named query\r\n\r\nA question that was raised by the work in #1938 is whether you should be able to grant a permission like `insert-row` at the instance or database level - and if so, what does that look like? I think you should be able to do that, it doesn't make sense to have to grant it explicitly for every single table.\r\n\r\nSo maybe `takes_table` and `takes_database` are the right names here? But `table` is still bad because it doesn't reflect views and canned queries.\r\n\r\nOne thought is to use `resource` - but that will require a bunch of breaking changes to the existing APIs which treat resource as a tuple. Now's the best time to do that though before Datasette 1.0.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343722020", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343722020, "node_id": "IC_kwDOBm6k_c5QF5Ik", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T01:36:05Z", "updated_at": "2022-12-09T01:36:16Z", "author_association": "OWNER", "body": "I originally added `permissions.py` for the permission debug tool in https://github.com/simonw/datasette/commit/c51d9246b996a2831c9bd6a1e205f6cb48b9a5f3 - I don't think anything else uses it yet.\r\n\r\n- #1881", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1939#issuecomment-1343721522", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1939", "id": 1343721522, "node_id": "IC_kwDOBm6k_c5QF5Ay", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-09T01:35:15Z", "updated_at": "2022-12-09T01:35:15Z", "author_association": "OWNER", "body": "One concern I have about this: there are a bunch of existing plugins that do stuff with permissions that won't currently be using this hook.\r\n\r\nDo I break those plugins, forcing new releases of them for compatibility with Datasette 1.0?\r\n\r\nOr maybe I keep them working, but until they've upgraded to register their permissions there are things about them that won't work - e.g. you won't be able to configure their permissions in `metadata.yml` until they release something that does this hook.\r\n\r\nBest thing is probably for me to get this working in core first and then evaluate the impact it would have on existing plugins once I have some running code.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1485757511, "label": "register_permissions(datasette) plugin hook"}, "performed_via_github_app": null}