Agrego carpeta del source sql de la Base de Datos

This commit is contained in:
Pablo
2026-08-22 19:10:49 -03:00
parent 11e36bd6c2
commit 88d724fbcf
94 changed files with 7820 additions and 0 deletions
@@ -0,0 +1,39 @@
-- ============================================================================
-- internal.clean_expired_sessions
-- ============================================================================
-- PROPÓSITO
-- Elimina todas las sesiones cuya fecha de expiración ya pasó. Pensada
-- para ejecutarse periódicamente por cron.
--
-- El job de cron que la dispara (ten_day_session_cleanup_job, días
-- 1, 11 y 21 de cada mes a las 00:00) se versiona en
-- cron/auth/ten_day_session_cleanup_job.sql.
--
-- PARÁMETROS
-- Ninguno.
--
-- AUTORIZACIÓN
-- No aplica (función interna invocada por cron).
--
-- ERRORES (RAISE EXCEPTION)
-- Ninguno.
--
-- RETORNA
-- void.
--
-- EFECTOS SECUNDARIOS
-- DELETE en internal.sesiones de las filas con expires_at < NOW().
-- ============================================================================
create OR REPLACE function internal.clean_expired_sessions() returns void
security definer
SET search_path = internal, pg_catalog
language plpgsql
as
$$
BEGIN
-- Elimina todas las sesiones cuya fecha de expiración es anterior a la actual.
DELETE FROM internal.sesiones
WHERE expires_at < NOW();
END;
$$;
@@ -0,0 +1,44 @@
-- ============================================================================
-- internal.clean_old_sessions_on_new_login
-- ============================================================================
-- PROPÓSITO
-- Trigger function: al insertar una nueva sesión, elimina cualquier otra
-- sesión previa del mismo usuario. Garantiza que cada usuario tiene a lo
-- sumo una sesión activa.
--
-- El trigger que la invoca (trg_clean_old_sessions, BEFORE INSERT on
-- internal.sesiones) se versiona en
-- triggers/auth/trg_clean_old_sessions.sql.
--
-- PARÁMETROS
-- Implícitos del trigger (NEW.usuario_id, NEW.token).
--
-- AUTORIZACIÓN
-- No aplica (es trigger).
--
-- ERRORES (RAISE EXCEPTION)
-- Ninguno.
--
-- RETORNA
-- trigger (la fila NEW para continuar el INSERT).
--
-- EFECTOS SECUNDARIOS
-- DELETE en internal.sesiones de cualquier sesión del mismo usuario con
-- token distinto al recién insertado.
-- ============================================================================
create OR REPLACE function internal.clean_old_sessions_on_new_login() returns trigger
security definer
set search_path = internal, pg_catalog
language plpgsql
as
$$
BEGIN
-- Esto asegura que solo la sesión actual (la que se está creando) permanezca.
DELETE FROM internal.sesiones
WHERE usuario_id = NEW.usuario_id
AND token IS DISTINCT FROM NEW.token;
RETURN NEW;
END;
$$;
@@ -0,0 +1,39 @@
-- ============================================================================
-- internal.create_password_hash
-- ============================================================================
-- PROPÓSITO
-- Devuelve el hash bcrypt de una contraseña en texto plano. Usa
-- crypt() + gen_salt('bf') del módulo pgcrypto, que vive en el schema
-- extensions.
--
-- Helper interno usado por internal.fc_insertar_usuario (vía
-- public.fc_insertar_usuario) y por funciones futuras de cambio de
-- contraseña.
--
-- PARÁMETROS
-- p_password_plain TEXT contraseña en claro.
--
-- AUTORIZACIÓN
-- Función interna, sin validación propia. Pensada para ser llamada por
-- otras funciones server-side, no por el cliente directamente.
--
-- ERRORES (RAISE EXCEPTION)
-- Ninguno propio.
--
-- RETORNA
-- TEXT con el hash bcrypt.
--
-- EFECTOS SECUNDARIOS
-- Ninguno.
-- ============================================================================
CREATE OR REPLACE FUNCTION internal.create_password_hash(p_password_plain TEXT)
RETURNS TEXT
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = extensions, public
AS $$
BEGIN
RETURN crypt(p_password_plain, gen_salt('bf'::text));
END;
$$;
@@ -0,0 +1,45 @@
-- ============================================================================
-- internal.validar_token
-- ============================================================================
-- PROPÓSITO
-- Dado un token de sesión, devuelve el rol del usuario asociado si la
-- sesión está vigente. Si el token no existe o ya expiró, devuelve NULL.
-- Helper interno usado por internal.validate_permission y por funciones
-- públicas que necesitan saber el rol del actor.
--
-- PARÁMETROS
-- p_token UUID token de sesión.
--
-- AUTORIZACIÓN
-- Función interna, sin validación propia.
--
-- ERRORES (RAISE EXCEPTION)
-- Ninguno.
--
-- RETORNA
-- TEXT con el rol del usuario, o NULL si el token es inválido o expiró.
--
-- EFECTOS SECUNDARIOS
-- Ninguno (STABLE).
-- ============================================================================
CREATE OR REPLACE FUNCTION internal.validar_token(p_token uuid)
RETURNS text
LANGUAGE plpgsql
STABLE SECURITY DEFINER
SET search_path TO 'public'
AS $function$
DECLARE
v_rol TEXT;
BEGIN
SELECT u.rol
FROM public.usuarios u
JOIN internal.sesiones s ON s.usuario_id = u.id
AND s.token = p_token
AND s.expires_at > NOW()
INTO v_rol;
-- Retorna el rol si el token es válido, de lo contrario, retorna NULL
RETURN v_rol;
END;
$function$
;
@@ -0,0 +1,62 @@
-- ============================================================================
-- internal.validate_permission
-- ============================================================================
-- PROPÓSITO
-- Valida que el portador del token tenga permiso para ejecutar una acción
-- dada. Rebota con excepción si el token es inválido, si la acción no
-- está registrada, o si el rol del usuario no está autorizado.
--
-- Es la pieza central del control de acceso: toda función pública (fc_*)
-- la invoca al inicio.
--
-- PARÁMETROS
-- p_token UUID token de sesión del actor.
-- p_accion TEXT nombre de la acción a validar (clave en internal.permisos).
--
-- AUTORIZACIÓN
-- Función interna; ella misma es el validador de autorización.
--
-- ERRORES (RAISE EXCEPTION)
-- - 'Token de sesión inválido o expirado'
-- - 'Error interno: acción no reconocida: X'
-- - 'No tienes internal.permisos para realizar esta acción'
-- (NOTA: el texto del error contiene "internal.permisos" por un error
-- histórico de redacción; se refiere a permisos en general.)
--
-- RETORNA
-- void si el actor tiene permiso. Si no, rebota antes de retornar.
--
-- EFECTOS SECUNDARIOS
-- Ninguno (STABLE).
-- ============================================================================
CREATE OR REPLACE FUNCTION internal.validate_permission(p_token UUID, p_accion TEXT)
RETURNS void
LANGUAGE plpgsql
STABLE
SECURITY DEFINER
SET search_path TO public
AS $$
DECLARE
v_rol TEXT;
v_roles_permitidos TEXT[];
BEGIN
SELECT internal.validar_token(p_token) INTO v_rol;
IF v_rol IS NULL THEN
RAISE EXCEPTION 'Token de sesión inválido o expirado';
END IF;
SELECT roles_permitidos INTO v_roles_permitidos
FROM internal.permisos
WHERE accion = p_accion;
IF v_roles_permitidos IS NULL THEN
RAISE EXCEPTION 'Error interno: acción no reconocida: %', p_accion;
END IF;
IF v_rol <> ALL(v_roles_permitidos) THEN
RAISE EXCEPTION 'No tienes internal.permisos para realizar esta acción';
END IF;
END;
$$;