Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -3,12 +3,13 @@ name: metabase_bulk_add_users_to_group
|
||||
kind: pipeline
|
||||
lang: py
|
||||
domain: pipelines
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
purity: impure
|
||||
signature: "def metabase_bulk_add_users_to_group(client: MetabaseClient, group: int | str, targets: list[dict], send_reset_existing: bool = False) -> list[dict]"
|
||||
description: "Crea (si faltan) y añade al Permission Group dado una lista de usuarios. Idempotente: usuarios existentes se re-añaden solo si no son miembros. Soporta resolver group por id o por nombre (substring case-insensitive). Opcionalmente reenvia mail de reset a los ya existentes."
|
||||
tags: [metabase, users, groups, bulk]
|
||||
uses_functions:
|
||||
- clean_email_py_core
|
||||
- metabase_list_groups_py_infra
|
||||
- metabase_list_users_py_infra
|
||||
- metabase_get_group_py_infra
|
||||
@@ -79,3 +80,8 @@ Cuando tengas que dar de alta o re-añadir N usuarios al mismo Permission Group
|
||||
- `send_reset_existing=True` solo afecta a los `status="existing"`. Los `status="created"` no reciben reset (ya recibieron invitacion).
|
||||
- `group` por nombre (str): si el substring matchea 0 o >1 grupos -> `ValueError`. Preferir `group_id` (int) si hay nombres ambiguos.
|
||||
- La respuesta de `metabase_list_users` puede ser un dict con key `data` o directamente la lista, dependiendo de la version de Metabase. El pipeline maneja ambos formatos.
|
||||
- Desde v1.1.0 cada `target["email"]` pasa por `clean_email` antes de cualquier llamada: strippea espacios, angle brackets `<...>`, comillas y normaliza a minusculas. Si la limpieza falla (ValueError) la fila sale como `status="create_failed"` sin tocar Metabase. Esto absorbe TSVs/CSVs con formato Outlook (`" <foo@bar.com>"`) que antes provocaban 400 Bad Request al POST /api/user.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- v1.1.0 (2026-05-28) — integra `clean_email_py_core` para normalizar emails de cada target. Absorbe `<...>`, comillas y whitespace antes del POST a Metabase. Fix tras incidente real con TSV de 90 jefes de centro donde 1 fila tenia `" <eaznarez@mutuamadmotor.com>"` y rompia create_user con 400.
|
||||
|
||||
@@ -12,6 +12,7 @@ import os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
import httpx
|
||||
from core import clean_email
|
||||
from metabase import (
|
||||
MetabaseClient,
|
||||
metabase_list_groups,
|
||||
@@ -39,6 +40,10 @@ def metabase_bulk_add_users_to_group(
|
||||
group: group_id (int) o nombre del grupo (str, substring
|
||||
case-insensitive). Debe matchear exactamente 1 grupo.
|
||||
targets: lista de dicts con keys first_name, last_name, email.
|
||||
El email se normaliza via clean_email (strip whitespace,
|
||||
angle brackets `<...>`, comillas, lowercase). Si el raw
|
||||
es invalido, esa fila sale como status=create_failed sin
|
||||
hacer ninguna llamada a Metabase.
|
||||
send_reset_existing: si True, reenvia POST /api/session/forgot_password
|
||||
a los usuarios ya existentes (no a los recien
|
||||
creados, que ya recibieron invitacion).
|
||||
@@ -93,11 +98,10 @@ def metabase_bulk_add_users_to_group(
|
||||
for target in targets:
|
||||
first_name = target["first_name"]
|
||||
last_name = target["last_name"]
|
||||
email = target["email"]
|
||||
email_lower = email.lower()
|
||||
raw_email = target["email"]
|
||||
|
||||
row: dict = {
|
||||
"email": email,
|
||||
"email": raw_email,
|
||||
"user_id": None,
|
||||
"status": None,
|
||||
"membership": None,
|
||||
@@ -105,6 +109,19 @@ def metabase_bulk_add_users_to_group(
|
||||
"error": None,
|
||||
}
|
||||
|
||||
# Normalizar email (strip whitespace, <...>, comillas, lowercase).
|
||||
# Si el raw es invalido (no parseable como email), saltar con error.
|
||||
try:
|
||||
email = clean_email(raw_email)
|
||||
except ValueError as exc:
|
||||
row["status"] = "create_failed"
|
||||
row["membership"] = "skipped"
|
||||
row["error"] = str(exc)
|
||||
results.append(row)
|
||||
continue
|
||||
row["email"] = email
|
||||
email_lower = email # ya lowercase tras clean_email
|
||||
|
||||
# Determinar si el usuario ya existe
|
||||
if email_lower in by_email:
|
||||
uid = by_email[email_lower]["id"]
|
||||
|
||||
Reference in New Issue
Block a user