--- name: metabase_update_collection_graph kind: function lang: py domain: infra version: "1.0.0" purity: impure signature: "def metabase_update_collection_graph(client: MetabaseClient, graph: dict, namespace: str | None = None) -> dict" description: "Actualiza el grafo de permisos de colecciones en Metabase. Endpoint: PUT /api/collection/graph. El campo revision en el graph es obligatorio — el servidor rechaza con 409 si no coincide con el actual. Soporta namespace para snippet collections." tags: [metabase, permissions, collections, graph, access-control, update, api, python] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [] params: - name: client desc: "instancia autenticada de MetabaseClient con permisos de superusuario" - name: graph desc: "dict con el grafo completo incluyendo el campo revision actual. Debe obtenerse vía metabase_get_collection_graph justo antes de modificar" - name: namespace desc: "namespace opcional: 'snippets' para snippet collections, None para colecciones regulares. Debe coincidir con el namespace usado en el GET" output: "dict: nuevo grafo tras la actualización con revision incrementado" tested: false tests: [] test_file_path: "" file_path: "python/functions/metabase/permissions.py" --- ## Ejemplo ```python graph = metabase_get_collection_graph(client) # Dar acceso write al grupo 3 sobre la colección 5 graph["groups"]["3"]["5"] = "write" updated = metabase_update_collection_graph(client, graph) print("nueva revision:", updated["revision"]) # Para snippet collections: graph = metabase_get_collection_graph(client, namespace="snippets") graph["groups"]["3"]["root"] = "write" updated = metabase_update_collection_graph(client, graph, namespace="snippets") ``` ## Control de concurrencia por revision El campo `graph["revision"]` es el mecanismo de optimistic locking nativo de Metabase. **Patrón obligatorio:** 1. `graph = metabase_get_collection_graph(client)` — GET fresco 2. Modificar `graph["groups"][group_id][collection_id] = "read" | "write" | "none"` 3. `graph = metabase_update_collection_graph(client, graph)` — PUT con revision **Nunca cachear el graph.** Si otro proceso modificó el graph entre el GET y el PUT, Metabase devuelve HTTP 409 Conflict y el caller debe reintentar desde el GET. ### Niveles de acceso para colecciones - `"write"` — el grupo puede ver y editar contenido de la colección - `"read"` — el grupo puede ver pero no editar - `"none"` — sin acceso (la colección es invisible para el grupo) El campo `"root"` como collection_id hace referencia a la colección raíz "Our analytics".