feat: Implement user management service and frontend integration

- Added UserService to manage Keycloak users with license validation in the backend.
- Created API client for user management in the frontend.
- Developed user management page with functionalities to create, update, delete, and list users.
- Implemented user statistics retrieval and display.
- Added dialogs for user creation, editing, password change, and deletion confirmation.
This commit is contained in:
2026-01-13 09:56:53 -06:00
parent 34e71b3114
commit f812d71508
10 changed files with 1759 additions and 108 deletions

View File

@@ -11,6 +11,7 @@
# 5. Tenant y Company en PostgreSQL
# 6. Relación usuario-tenant en tabla user_tenants
# 7. Actualización del tenant_id del usuario con el valor real
# 8. Licencia Enterprise para el tenant (ilimitada, 1 año de vigencia)
#
# Requisitos:
# - Keycloak corriendo en http://localhost:8080
@@ -22,7 +23,10 @@
# se actualiza con el ID real del tenant creado en PostgreSQL.
###############################################################################
# set -e # Comentado para permitir que el script continúe aunque algunos comandos fallen (ej: mapper ya existe)
set -euo pipefail # Modo strict: exit on error, undefined vars, pipe failures
# Trap para cleanup en caso de error
trap 'echo -e "\n${RED}✗ Error en línea $LINENO. Script abortado.${NC}" >&2' ERR
# Colores para output
RED='\033[0;31m'
@@ -30,6 +34,84 @@ GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
###############################################################################
# Validar dependencias requeridas
###############################################################################
check_dependencies() {
local missing_deps=()
command -v jq >/dev/null 2>&1 || missing_deps+=("jq")
command -v curl >/dev/null 2>&1 || missing_deps+=("curl")
command -v docker >/dev/null 2>&1 || missing_deps+=("docker")
if [ ${#missing_deps[@]} -ne 0 ]; then
echo -e "${RED}✗ Error: Dependencias faltantes: ${missing_deps[*]}${NC}" >&2
echo -e "${YELLOW}Instala las dependencias faltantes antes de continuar.${NC}" >&2
exit 1
fi
}
check_dependencies
###############################################################################
# Funciones auxiliares
###############################################################################
# Ejecutar SQL en PostgreSQL via Docker
exec_pg_sql() {
local sql="$1"
docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 \
psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" \
-t -c "${sql}" 2>&1
}
# Crear mapper de tenant_id para un cliente
create_tenant_mapper() {
local client_id="$1"
local client_name="$2"
echo "Configurando mapper para ${client_name}..."
# Verificar si el mapper ya existe
local mappers
mappers=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${client_id}/protocol-mappers/models" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json")
if echo "$mappers" | jq -e '.[] | select(.name == "tenant-id-mapper")' >/dev/null 2>&1; then
echo -e "${YELLOW}⚠ Mapper tenant_id ya existe para ${client_name}${NC}"
return 0
fi
# Crear mapper
local response
response=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${client_id}/protocol-mappers/models" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "tenant-id-mapper",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"config": {
"user.attribute": "tenant_id",
"claim.name": "tenant_id",
"jsonType.label": "String",
"id.token.claim": "true",
"access.token.claim": "true",
"userinfo.token.claim": "true"
}
}')
local http_code
http_code=$(echo "$response" | tail -n1)
if [ "$http_code" = "201" ]; then
echo -e "${GREEN}✓ Mapper tenant_id creado para ${client_name}${NC}"
else
echo -e "${YELLOW}⚠ No se pudo crear mapper para ${client_name} (HTTP ${http_code})${NC}"
fi
}
# Variables de configuración
KEYCLOAK_URL="${KEYCLOAK_URL:-http://localhost:8080/kcauth}"
KEYCLOAK_ADMIN="${KEYCLOAK_ADMIN:-admin}"
@@ -71,7 +153,9 @@ while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
break
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
echo "Intento $RETRY_COUNT/$MAX_RETRIES..."
if [ $((RETRY_COUNT % 5)) -eq 0 ]; then
echo "Esperando Keycloak... ($RETRY_COUNT/$MAX_RETRIES)"
fi
sleep 2
done
@@ -92,7 +176,7 @@ TOKEN_RESPONSE=$(curl -s -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-
-d "grant_type=password" \
-d "client_id=admin-cli")
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | grep -o '"access_token":"[^"]*' | sed 's/"access_token":"//')
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token // empty')
if [ -z "$ACCESS_TOKEN" ]; then
echo -e "${RED}✗ Error: No se pudo obtener el token de acceso${NC}"
@@ -112,8 +196,8 @@ USER_PROFILE=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/us
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json")
# Verificar si tenant_id existe
TENANT_ID_EXISTS=$(echo "$USER_PROFILE" | grep -q "\"name\":\"tenant_id\"" && echo "true" || echo "false")
# Verificar si tenant_id existe usando jq
TENANT_ID_EXISTS=$(echo "$USER_PROFILE" | jq -e '.attributes[]? | select(.name == "tenant_id")' >/dev/null 2>&1 && echo "true" || echo "false")
if [ "$TENANT_ID_EXISTS" = "false" ]; then
echo "Agregando atributo tenant_id al User Profile..."
@@ -160,9 +244,9 @@ BACKEND_CLIENT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json")
if echo "$BACKEND_CLIENT_EXISTS" | grep -q "\"clientId\":\"anexo76-backend\""; then
if echo "$BACKEND_CLIENT_EXISTS" | jq -e '.[] | select(.clientId == "anexo76-backend")' >/dev/null 2>&1; then
echo -e "${YELLOW}⚠ Cliente Backend ya existe${NC}"
BACKEND_CLIENT_ID=$(echo "$BACKEND_CLIENT_EXISTS" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//')
BACKEND_CLIENT_ID=$(echo "$BACKEND_CLIENT_EXISTS" | jq -r '.[0].id')
else
CREATE_BACKEND=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
@@ -198,7 +282,7 @@ else
BACKEND_CLIENT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=anexo76-backend" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json")
BACKEND_CLIENT_ID=$(echo "$BACKEND_CLIENT_EXISTS" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//')
BACKEND_CLIENT_ID=$(echo "$BACKEND_CLIENT_EXISTS" | jq -r '.[0].id')
else
echo -e "${RED}✗ Error al crear cliente Backend (HTTP ${HTTP_CODE})${NC}"
fi
@@ -208,7 +292,7 @@ fi
if [ -n "$BACKEND_CLIENT_ID" ]; then
BACKEND_SECRET=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${BACKEND_CLIENT_ID}/client-secret" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" | grep -o '"value":"[^"]*' | sed 's/"value":"//')
-H "Content-Type: application/json" | jq -r '.value // empty')
echo -e "${GREEN}✓ Backend Client ID: anexo76-backend${NC}"
echo -e "${GREEN}✓ Backend Client Secret: ${BACKEND_SECRET}${NC}"
@@ -252,9 +336,9 @@ FRONTEND_CLIENT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json")
if echo "$FRONTEND_CLIENT_EXISTS" | grep -q "\"clientId\":\"anexo76-frontend\""; then
if echo "$FRONTEND_CLIENT_EXISTS" | jq -e '.[] | select(.clientId == "anexo76-frontend")' >/dev/null 2>&1; then
echo -e "${YELLOW}⚠ Cliente Frontend ya existe${NC}"
FRONTEND_CLIENT_ID=$(echo "$FRONTEND_CLIENT_EXISTS" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//')
FRONTEND_CLIENT_ID=$(echo "$FRONTEND_CLIENT_EXISTS" | jq -r '.[0].id')
else
CREATE_FRONTEND=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
@@ -293,7 +377,7 @@ else
FRONTEND_CLIENT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=anexo76-frontend" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json")
FRONTEND_CLIENT_ID=$(echo "$FRONTEND_CLIENT_EXISTS" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//')
FRONTEND_CLIENT_ID=$(echo "$FRONTEND_CLIENT_EXISTS" | jq -r '.[0].id')
else
echo -e "${RED}✗ Error al crear cliente Frontend (HTTP ${HTTP_CODE})${NC}"
echo "Respuesta del servidor: $RESPONSE_BODY"
@@ -307,83 +391,12 @@ echo -e "\n${YELLOW}[5/8] Configurando mappers para tenant_id...${NC}"
# 4.1 Configurar mapper para Backend
if [ -n "$BACKEND_CLIENT_ID" ]; then
echo "Configurando mapper para Backend..."
# Verificar si el mapper tenant_id ya existe en el cliente
MAPPER_TENANT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${BACKEND_CLIENT_ID}/protocol-mappers/models" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" | grep -o "\"name\":\"tenant-id-mapper\"")
if [ -z "$MAPPER_TENANT_EXISTS" ]; then
# Crear mapper para tenant_id directamente en el cliente
CREATE_MAPPER_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${BACKEND_CLIENT_ID}/protocol-mappers/models" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "tenant-id-mapper",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"config": {
"user.attribute": "tenant_id",
"claim.name": "tenant_id",
"jsonType.label": "String",
"id.token.claim": "true",
"access.token.claim": "true",
"userinfo.token.claim": "true"
}
}')
HTTP_CODE=$(echo "$CREATE_MAPPER_RESPONSE" | tail -n1)
if [ "$HTTP_CODE" = "201" ]; then
echo -e "${GREEN}✓ Mapper tenant_id creado para Backend${NC}"
else
echo -e "${YELLOW}⚠ Error al crear mapper para Backend (HTTP ${HTTP_CODE})${NC}"
echo "Respuesta: $(echo "$CREATE_MAPPER_RESPONSE" | head -n -1)"
fi
else
echo -e "${YELLOW}⚠ Mapper tenant_id ya existe para Backend${NC}"
fi
create_tenant_mapper "$BACKEND_CLIENT_ID" "Backend"
fi
# 4.2 Configurar mapper para Frontend
if [ -n "$FRONTEND_CLIENT_ID" ]; then
echo "Configurando mapper para Frontend..."
# Verificar si el mapper tenant_id ya existe en el cliente
MAPPER_TENANT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${FRONTEND_CLIENT_ID}/protocol-mappers/models" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" | grep -o "\"name\":\"tenant-id-mapper\"")
if [ -z "$MAPPER_TENANT_EXISTS" ]; then
# Crear mapper para tenant_id directamente en el cliente
CREATE_MAPPER_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${FRONTEND_CLIENT_ID}/protocol-mappers/models" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "tenant-id-mapper",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"config": {
"user.attribute": "tenant_id",
"claim.name": "tenant_id",
"jsonType.label": "String",
"id.token.claim": "true",
"access.token.claim": "true",
"userinfo.token.claim": "true"
}
}')
HTTP_CODE=$(echo "$CREATE_MAPPER_RESPONSE" | tail -n1)
if [ "$HTTP_CODE" = "201" ]; then
echo -e "${GREEN}✓ Mapper tenant_id creado para Frontend${NC}"
else
echo -e "${YELLOW}⚠ Error al crear mapper para Frontend (HTTP ${HTTP_CODE})${NC}"
echo "Respuesta: $(echo "$CREATE_MAPPER_RESPONSE" | head -n -1)"
fi
else
echo -e "${YELLOW}⚠ Mapper tenant_id ya existe para Frontend${NC}"
fi
create_tenant_mapper "$FRONTEND_CLIENT_ID" "Frontend"
fi
@@ -397,9 +410,9 @@ USER_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/use
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json")
if echo "$USER_EXISTS" | grep -q "\"username\":\"${DEMO_USERNAME}\""; then
if echo "$USER_EXISTS" | jq -e '.[] | select(.username == "'"${DEMO_USERNAME}"'")' >/dev/null 2>&1; then
echo -e "${YELLOW}⚠ Usuario demo ya existe, actualizando...${NC}"
USER_ID=$(echo "$USER_EXISTS" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//')
USER_ID=$(echo "$USER_EXISTS" | jq -r '.[0].id')
# Actualizar usuario existente
curl -s -X PUT "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users/${USER_ID}" \
@@ -455,7 +468,7 @@ else
USER_RESPONSE=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users?username=${DEMO_USERNAME}" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json")
USER_ID=$(echo "$USER_RESPONSE" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//')
USER_ID=$(echo "$USER_RESPONSE" | jq -r '.[0].id')
else
echo -e "${RED}✗ Error al crear usuario (HTTP ${HTTP_CODE})${NC}"
echo "Respuesta: $CREATE_RESPONSE"
@@ -470,14 +483,14 @@ echo -e "${GREEN}✓ Keycloak User ID: ${USER_ID}${NC}"
###############################################################################
# 7. Agregar atributo tenant_id al usuario
###############################################################################
echo -e "\n${YELLOW}[7/8] Configurando atributo tenant_id para usuario demo...${NC}"
echo -e "\n${YELLOW}[7/9] Configurando atributo tenant_id para usuario demo...${NC}"
# Nota: El tenant_id se agregará después de crear el tenant en PostgreSQL
###############################################################################
# 8. Crear tenant y company en PostgreSQL
###############################################################################
echo -e "\n${YELLOW}[8/8] Creando tenant y company en PostgreSQL...${NC}"
echo -e "\n${YELLOW}[8/9] Creando tenant y company en PostgreSQL...${NC}"
# Esperar a que PostgreSQL esté listo
echo "Esperando a que PostgreSQL esté disponible..."
@@ -491,7 +504,9 @@ while [ $PG_RETRY_COUNT -lt $MAX_PG_RETRIES ]; do
break
fi
PG_RETRY_COUNT=$((PG_RETRY_COUNT + 1))
echo "Intento $PG_RETRY_COUNT/$MAX_PG_RETRIES..."
if [ $((PG_RETRY_COUNT % 10)) -eq 0 ]; then
echo "Esperando PostgreSQL... ($PG_RETRY_COUNT/$MAX_PG_RETRIES)"
fi
sleep 1
done
@@ -502,13 +517,16 @@ fi
# Insertar o actualizar tenant
echo "Insertando tenant en PostgreSQL..."
docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -c "INSERT INTO core.tenants (name, slug, type, keycloak_realm, contact_email, is_active, created_at, updated_at) VALUES ('${TENANT_NAME}', '${TENANT_SLUG}', 'SHARED'::tenanttype, '${KEYCLOAK_REALM}', '${DEMO_EMAIL}', true, now(), now()) ON CONFLICT (slug) DO UPDATE SET name = EXCLUDED.name, contact_email = EXCLUDED.contact_email, updated_at = CURRENT_TIMESTAMP;" 2>&1
exec_pg_sql "INSERT INTO core.tenants (name, slug, type, keycloak_realm, contact_email, is_active, created_at, updated_at) VALUES ('${TENANT_NAME}', '${TENANT_SLUG}', 'SHARED'::tenanttype, '${KEYCLOAK_REALM}', '${DEMO_EMAIL}', true, now(), now()) ON CONFLICT (slug) DO UPDATE SET name = EXCLUDED.name, contact_email = EXCLUDED.contact_email, updated_at = CURRENT_TIMESTAMP;" >/dev/null
# Obtener el ID del tenant con mejor manejo de errores
echo "Obteniendo ID del tenant..."
TENANT_ID_RESULT=$(docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -t -c "SELECT id FROM core.tenants WHERE slug = '${TENANT_SLUG}';" 2>&1)
set +e
TENANT_ID_RESULT=$(exec_pg_sql "SELECT id FROM core.tenants WHERE slug = '${TENANT_SLUG}';")
TENANT_QUERY_STATUS=$?
set -e
if [ $? -ne 0 ]; then
if [ $TENANT_QUERY_STATUS -ne 0 ]; then
echo -e "${RED}✗ Error al consultar el tenant:${NC}"
echo "$TENANT_ID_RESULT"
echo -e "${YELLOW}Verificando si la tabla existe...${NC}"
@@ -529,18 +547,18 @@ fi
echo -e "${GREEN}✓ Tenant ID: ${TENANT_ID}${NC}"
# Insertar company si no existe
COMPANY_EXISTS=$(docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -t -c "SELECT COUNT(*) FROM a76.company WHERE tenant_id = ${TENANT_ID};")
COMPANY_EXISTS=$(exec_pg_sql "SELECT COUNT(*) FROM a76.company WHERE tenant_id = ${TENANT_ID};")
COMPANY_EXISTS=$(echo "$COMPANY_EXISTS" | xargs)
if [ "$COMPANY_EXISTS" = "0" ]; then
docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -c "INSERT INTO a76.company (tenant_id, name, rfc, is_service_company, created_at, updated_at) VALUES (${TENANT_ID}, '${COMPANY_NAME}', '${COMPANY_RFC}', false, now(), now());" 2>&1
exec_pg_sql "INSERT INTO a76.company (tenant_id, name, rfc, is_service_company, created_at, updated_at) VALUES (${TENANT_ID}, '${COMPANY_NAME}', '${COMPANY_RFC}', false, now(), now());" >/dev/null
echo -e "${GREEN}✓ Company creada${NC}"
else
echo -e "${YELLOW}⚠ Company ya existe para este tenant${NC}"
fi
# Obtener información de la company
COMPANY_INFO=$(docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -t -c "SELECT id, name FROM a76.company WHERE tenant_id = ${TENANT_ID} LIMIT 1;")
COMPANY_INFO=$(exec_pg_sql "SELECT id, name FROM a76.company WHERE tenant_id = ${TENANT_ID} LIMIT 1;")
echo -e "${GREEN}✓ Company: ${COMPANY_INFO}${NC}"
@@ -561,10 +579,62 @@ echo -e "${GREEN}✓ Atributo tenant_id asignado al usuario${NC}"
# Agregar relación usuario-tenant en la base de datos
echo -e "\n${YELLOW}Creando relación usuario-tenant en la base de datos...${NC}"
docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -c "INSERT INTO core.user_tenants (keycloak_user_id, tenant_id, company_id, role, is_active, created_at, updated_at) VALUES ('${USER_ID}', ${TENANT_ID}, 1, 'admin', true, now(), now()) ON CONFLICT (keycloak_user_id, tenant_id, company_id) DO UPDATE SET is_active = true, updated_at = CURRENT_TIMESTAMP;" 2>&1
exec_pg_sql "INSERT INTO core.user_tenants (keycloak_user_id, tenant_id, company_id, role, is_active, created_at, updated_at) VALUES ('${USER_ID}', ${TENANT_ID}, 1, 'admin', true, now(), now()) ON CONFLICT (keycloak_user_id, tenant_id, company_id) DO UPDATE SET is_active = true, updated_at = CURRENT_TIMESTAMP;" >/dev/null
echo -e "${GREEN}✓ Relación usuario-tenant creada en la base de datos${NC}"
###############################################################################
# 9. Crear licencia Enterprise para el tenant
###############################################################################
echo -e "\n${YELLOW}[9/9] Creando licencia Enterprise para el tenant...${NC}"
# Calcular fechas de inicio y expiración (1 año desde hoy)
LICENSE_START_DATE=$(date -u +"%Y-%m-%d %H:%M:%S")
LICENSE_EXPIRE_DATE=$(date -u -d "+1 year" +"%Y-%m-%d %H:%M:%S")
# Verificar si ya existe una licencia para este tenant
LICENSE_EXISTS=$(exec_pg_sql "SELECT COUNT(*) FROM core.licenses WHERE tenant_id = ${TENANT_ID};")
LICENSE_EXISTS=$(echo "$LICENSE_EXISTS" | xargs)
if [ "$LICENSE_EXISTS" = "0" ]; then
# Crear licencia Enterprise con límites ilimitados (valores muy altos)
set +e # Desactivar exit on error temporalmente
LICENSE_CREATE_OUTPUT=$(exec_pg_sql "INSERT INTO core.licenses (tenant_id, plan, status, max_users, max_storage_gb, max_monthly_operations, feature_api_access, feature_advanced_reports, feature_integrations, feature_dedicated_support, starts_at, expires_at, created_at, updated_at) VALUES (${TENANT_ID}, 'ENTERPRISE', 'ACTIVE', 999999, 999999, 999999, true, true, true, true, '${LICENSE_START_DATE}'::timestamp, '${LICENSE_EXPIRE_DATE}'::timestamp, now(), now());" 2>&1)
LICENSE_CREATE_STATUS=$?
set -e # Reactivar exit on error
if [ $LICENSE_CREATE_STATUS -eq 0 ]; then
echo -e "${GREEN}✓ Licencia Enterprise creada exitosamente${NC}"
echo -e "${GREEN} Plan: Enterprise${NC}"
echo -e "${GREEN} Usuarios: Ilimitados${NC}"
echo -e "${GREEN} Almacenamiento: Ilimitado${NC}"
echo -e "${GREEN} Operaciones mensuales: Ilimitadas${NC}"
echo -e "${GREEN} Inicio: ${LICENSE_START_DATE}${NC}"
echo -e "${GREEN} Expiración: ${LICENSE_EXPIRE_DATE}${NC}"
echo -e "${GREEN} Features: API, Reportes Avanzados, Integraciones, Soporte Dedicado${NC}"
else
echo -e "${RED}✗ Error al crear la licencia${NC}"
echo -e "${YELLOW}Detalle del error:${NC}"
echo "$LICENSE_CREATE_OUTPUT"
exit 1
fi
else
echo -e "${YELLOW}⚠ Ya existe una licencia para este tenant, actualizando a Enterprise...${NC}"
# Actualizar licencia existente a Enterprise
set +e # Desactivar exit on error temporalmente
exec_pg_sql "UPDATE core.licenses SET plan = 'ENTERPRISE', status = 'ACTIVE', max_users = 999999, max_storage_gb = 999999, max_monthly_operations = 999999, feature_api_access = true, feature_advanced_reports = true, feature_integrations = true, feature_dedicated_support = true, starts_at = '${LICENSE_START_DATE}'::timestamp, expires_at = '${LICENSE_EXPIRE_DATE}'::timestamp, updated_at = now() WHERE tenant_id = ${TENANT_ID};" >/dev/null 2>&1
LICENSE_UPDATE_STATUS=$?
set -e # Reactivar exit on error
if [ $LICENSE_UPDATE_STATUS -eq 0 ]; then
echo -e "${GREEN}✓ Licencia actualizada a Enterprise${NC}"
else
echo -e "${RED}✗ Error al actualizar la licencia${NC}"
exit 1
fi
fi
###############################################################################
# Resumen final
###############################################################################
@@ -598,6 +668,11 @@ echo -e " ${GREEN}✓${NC} tenant_id mapper para Frontend"
echo -e "\n${YELLOW}Configuración del usuario demo:${NC}"
echo -e " ${GREEN}${NC} tenant_id actualizado al ID real: ${TENANT_ID}"
echo -e " ${GREEN}${NC} Relación usuario-tenant creada (rol: admin)"
echo -e "\n${YELLOW}Licencia Enterprise:${NC}"
echo -e " ${GREEN}${NC} Plan: Enterprise (ilimitado)"
echo -e " ${GREEN}${NC} Status: Activa"
echo -e " ${GREEN}${NC} Features: API, Reportes Avanzados, Integraciones, Soporte Dedicado"
echo -e " ${GREEN}${NC} Vigencia: 1 año"
echo -e "\n${YELLOW}Puedes acceder al sistema en:${NC}"
echo -e " ${GREEN}http://localhost:5173${NC}"
echo -e "\n${GREEN}════════════════════════════════════════════════════════${NC}\n"