{"ok": true, "next": null, "rows": [{"id": "plugin_hooks:plugin-hook-register-events", "page": "plugin_hooks", "ref": "plugin-hook-register-events", "title": "register_events(datasette)", "content": "datasette  -  Datasette class \n                         \n                             You can use this to access plugin configuration options via  datasette.plugin_config(your_plugin_name) . \n                         \n                     \n                 \n                 This hook should return a list of  Event  subclasses that represent custom events that the plugin might send to the  datasette.track_event()  method. \n                 This example registers event subclasses for  ban-user  and  unban-user  events: \n                 from dataclasses import dataclass\nfrom datasette import hookimpl, Event\n\n\n@dataclass\nclass BanUserEvent(Event):\n    name = \"ban-user\"\n    user: dict\n\n\n@dataclass\nclass UnbanUserEvent(Event):\n    name = \"unban-user\"\n    user: dict\n\n\n@hookimpl\ndef register_events():\n    return [BanUserEvent, UnbanUserEvent] \n                 The plugin can then call  datasette.track_event(...)  to send a  ban-user  event: \n                 await datasette.track_event(\n    BanUserEvent(user={\"id\": 1, \"username\": \"cleverbot\"})\n)", "breadcrumbs": "[\"Plugin hooks\", \"Event tracking\"]", "references": "[]"}, {"id": "plugin_hooks:plugin-hook-register-token-handler", "page": "plugin_hooks", "ref": "plugin-hook-register-token-handler", "title": "register_token_handler(datasette)", "content": "datasette  -  Datasette class \n                         \n                             You can use this to access plugin configuration options via  datasette.plugin_config(your_plugin_name) . \n                         \n                     \n                 \n                 Return a  TokenHandler  instance to provide a custom token creation and verification backend. This hook can return a single  TokenHandler  or a list of them. \n                 The default  SignedTokenHandler  uses itsdangerous signed tokens ( dstok_  prefix). Plugins can provide alternative backends such as database-backed tokens that support revocation and auditing. \n                 from datasette import hookimpl, TokenHandler\n\n\nclass DatabaseTokenHandler(TokenHandler):\n    name = \"database\"\n\n    async def create_token(\n        self,\n        datasette,\n        actor_id,\n        *,\n        expires_after=None,\n        restrictions=None\n    ):\n        # Store token in database and return token string\n        ...\n\n    async def verify_token(self, datasette, token):\n        # Look up token in database, return actor dict or None\n        ...\n\n\n@hookimpl\ndef register_token_handler(datasette):\n    return DatabaseTokenHandler() \n                 The  create_token  method receives a  restrictions  argument which will be a  TokenRestrictions  instance or  None . \n                 Tokens can then be created and verified using  datasette.create_token()  and  datasette.verify_token() , which delegate to the registered handlers. If no  handler  is specified, the first handler is used according to  pluggy call-time ordering . Use the  handler  parameter to select a specific backend by name: \n                 # Uses first registered handler (default)\ntoken = await datasette.create_token(\"user123\")\n\n# Uses a specific handler by name\ntoken = await datasette.create_token(\n    \"user123\", handler=\"database\"\n)\n\n# Verification tries all handlers\nactor = await datasette.verify_token(token) \n                 If no handlers are registered,  create_token()  raises  RuntimeError . If the requested  handler  name is not found, it raises  ValueError .", "breadcrumbs": "[\"Plugin hooks\", \"Event tracking\"]", "references": "[{\"href\": \"https://pluggy.readthedocs.io/en/stable/#call-time-order\", \"label\": \"pluggy call-time ordering\"}]"}, {"id": "plugin_hooks:plugin-hook-track-event", "page": "plugin_hooks", "ref": "plugin-hook-track-event", "title": "track_event(datasette, event)", "content": "datasette  -  Datasette class \n                         \n                             You can use this to access plugin configuration options via  datasette.plugin_config(your_plugin_name) . \n                         \n                     \n                     \n                         event  -  Event \n                         \n                             Information about the event, represented as an instance of a subclass of the  Event  base class. \n                         \n                     \n                 \n                 This hook will be called any time an event is tracked by code that calls the  datasette.track_event(...)  internal method. \n                 The  event  object will always have the following properties: \n                 \n                     \n                         name : a string representing the name of the event, for example  logout  or  create-table . \n                     \n                     \n                         actor : a dictionary representing the actor that triggered the event, or  None  if the event was not triggered by an actor. \n                     \n                     \n                         created : a  datatime.datetime  object in the  timezone.utc  timezone representing the time the event object was created. \n                     \n                 \n                 Other properties on the event will be available depending on the type of event. You can also access those as a dictionary using  event.properties() . \n                 The events fired by Datasette core are  documented here . \n                 This example plugin logs details of all events to standard error: \n                 from datasette import hookimpl\nimport json\nimport sys\n\n\n@hookimpl\ndef track_event(event):\n    name = event.name\n    actor = event.actor\n    properties = event.properties()\n    msg = json.dumps(\n        {\n            \"name\": name,\n            \"actor\": actor,\n            \"properties\": properties,\n        }\n    )\n    print(msg, file=sys.stderr, flush=True) \n                 The function can also return an async function which will be awaited. This is useful for writing to a database. \n                 This example logs events to a  datasette_events  table in a database called  events . It uses the  startup(datasette)  hook to create that table if it does not exist. \n                 from datasette import hookimpl\nimport json\n\n\n@hookimpl\ndef startup(datasette):\n    async def inner():\n        db = datasette.get_database(\"events\")\n        await db.execute_write(\"\"\"\n            create table if not exists datasette_events (\n                id integer primary key,\n                event_type text,\n                created text,\n                actor text,\n                properties text\n            )\n        \"\"\")\n\n    return inner\n\n\n@hookimpl\ndef track_event(datasette, event):\n    async def inner():\n        db = datasette.get_database(\"events\")\n        properties = event.properties()\n        await db.execute_write(\n            \"\"\"\n            insert into datasette_events (event_type, created, actor, properties)\n            values (?, strftime('%Y-%m-%d %H:%M:%S', 'now'), ?, ?)\n        \"\"\",\n            (\n                event.name,\n                json.dumps(event.actor),\n                json.dumps(properties),\n            ),\n        )\n\n    return inner \n                 Example:  datasette-events-db", "breadcrumbs": "[\"Plugin hooks\", \"Event tracking\"]", "references": "[{\"href\": \"https://datasette.io/plugins/datasette-events-db\", \"label\": \"datasette-events-db\"}]"}], "truncated": false}