-- ============================================================================ -- GLM HUB — MIGRACIÓN: ACCESO AUTOMÁTICO POR DOMINIO -- ============================================================================ -- Ejecutar una sola vez sobre la base existente. -- Resultado: -- * Todo correo @gomezleemarketing.com entra automáticamente como Usuario. -- * glm_hub_authorized_users conserva solo administradores y bloqueos. -- * Los permisos internos de cada aplicación continúan fuera del Hub. -- ============================================================================ begin; comment on table public.glm_hub_authorized_users is 'Excepciones de acceso del GLM Hub: administradores activos y usuarios bloqueados. Los usuarios corporativos normales no requieren registro.'; -- Permite que cada persona consulte únicamente su propia excepción, incluyendo -- un posible bloqueo con is_active = false. drop policy if exists "GLM Hub users can read only their active access" on public.glm_hub_authorized_users; drop policy if exists "GLM Hub users can read their own control record" on public.glm_hub_authorized_users; create policy "GLM Hub users can read their own control record" on public.glm_hub_authorized_users for select to authenticated using ( email = lower(coalesce((select auth.jwt() ->> 'email'), '')) ); -- Garantiza los cinco administradores definidos. insert into public.glm_hub_authorized_users (email, full_name, role, is_active) values ('jgomez@gomezleemarketing.com', 'José Leopoldo Gómez', 'admin', true), ('iaracena@gomezleemarketing.com', 'Isaac Aracena', 'admin', true), ('ethen@gomezleemarketing.com', 'Eidan Then', 'admin', true), ('mgomez@gomezleemarketing.com', 'Máximo Gomez', 'admin', true), ('lmatos@gomezleemarketing.com', 'Luis Matos', 'admin', true) on conflict (email) do update set full_name = excluded.full_name, role = excluded.role, is_active = true, updated_at = now(); -- Los usuarios normales ya no requieren una fila. Se conservan administradores -- y bloqueos (member con is_active = false). delete from public.glm_hub_authorized_users where role = 'member' and is_active = true; create or replace function public.glm_hub_is_active_user() returns boolean language plpgsql stable security definer set search_path = '' as $$ declare v_email text; begin v_email := lower(coalesce(auth.jwt() ->> 'email', '')); return auth.uid() is not null and v_email ~ '^[a-z0-9.!#$%&''*+/=?^_`{|}~-]+@gomezleemarketing\.com$' and not exists ( select 1 from public.glm_hub_authorized_users as access where access.email = v_email and access.is_active = false ); end; $$; create or replace function public.glm_hub_is_admin() returns boolean language plpgsql stable security definer set search_path = '' as $$ declare v_email text; begin v_email := lower(coalesce(auth.jwt() ->> 'email', '')); return auth.uid() is not null and exists ( select 1 from public.glm_hub_authorized_users as access where access.email = v_email and access.role = 'admin' and access.is_active = true ); end; $$; alter function public.glm_hub_is_active_user() owner to postgres; alter function public.glm_hub_is_admin() owner to postgres; revoke all on function public.glm_hub_is_active_user() from public, anon; revoke all on function public.glm_hub_is_admin() from public, anon; grant execute on function public.glm_hub_is_active_user() to authenticated; grant execute on function public.glm_hub_is_admin() to authenticated; grant execute on function public.glm_hub_is_active_user() to service_role; grant execute on function public.glm_hub_is_admin() to service_role; -- Actualiza la solicitud de acceso para que un usuario corporativo no necesite -- existir previamente en glm_hub_authorized_users. create or replace function public.glm_hub_prepare_access_request(p_app_id uuid) returns jsonb language plpgsql volatile security definer set search_path = '' as $$ declare v_user_id uuid; v_email text; v_name text; v_control_name text; v_role text; v_is_active boolean; v_app_name text; v_app_category text; v_request_id uuid; begin v_user_id := auth.uid(); v_email := lower(coalesce(auth.jwt() ->> 'email', '')); if v_user_id is null or v_email = '' then return jsonb_build_object('ok', false, 'error', 'Tu sesión no es válida. Cierra sesión e inicia nuevamente.'); end if; if v_email !~ '^[a-z0-9.!#$%&''*+/=?^_`{|}~-]+@gomezleemarketing\.com$' then return jsonb_build_object('ok', false, 'error', 'Debes utilizar una cuenta corporativa de GomezLee Marketing.'); end if; select access.full_name, access.role, access.is_active into v_control_name, v_role, v_is_active from public.glm_hub_authorized_users as access where access.email = v_email limit 1; if found and v_is_active = false then return jsonb_build_object('ok', false, 'error', 'Tu acceso al GLM Hub está deshabilitado. Contacta a IT Support.'); end if; if coalesce(v_role, 'member') = 'admin' then return jsonb_build_object('ok', false, 'error', 'Los administradores no necesitan solicitar acceso desde el Hub.'); end if; v_name := coalesce( nullif(btrim(v_control_name), ''), nullif(btrim(auth.jwt() -> 'user_metadata' ->> 'full_name'), ''), nullif(btrim(auth.jwt() -> 'user_metadata' ->> 'name'), ''), split_part(v_email, '@', 1) ); select app.name, app.category into v_app_name, v_app_category from public.glm_hub_apps as app where app.id = p_app_id and app.visibility = 'published' limit 1; if not found then return jsonb_build_object('ok', false, 'error', 'La aplicación seleccionada ya no está publicada.'); end if; if exists ( select 1 from public.glm_hub_access_requests as request where request.requester_email = v_email and request.app_id = p_app_id and request.status = 'pending' ) then return jsonb_build_object( 'ok', false, 'code', 'PENDING_EXISTS', 'error', 'Ya existe una solicitud pendiente para esta aplicación.' ); end if; insert into public.glm_hub_access_requests ( requester_user_id, requester_name, requester_email, app_id, app_name, app_category ) values ( v_user_id, v_name, v_email, p_app_id, v_app_name, v_app_category ) returning id into v_request_id; return jsonb_build_object( 'ok', true, 'requestId', v_request_id, 'requesterName', v_name, 'requesterEmail', v_email, 'appName', v_app_name, 'appCategory', v_app_category ); end; $$; alter function public.glm_hub_prepare_access_request(uuid) owner to postgres; revoke all on function public.glm_hub_prepare_access_request(uuid) from public, anon; grant execute on function public.glm_hub_prepare_access_request(uuid) to authenticated; grant execute on function public.glm_hub_prepare_access_request(uuid) to service_role; notify pgrst, 'reload schema'; commit; -- ========================================================================== -- OPERACIONES FUTURAS -- ========================================================================== -- HACER ADMINISTRADOR: -- insert into public.glm_hub_authorized_users (email, full_name, role, is_active) -- values ('usuario@gomezleemarketing.com', 'Nombre del usuario', 'admin', true) -- on conflict (email) do update -- set full_name = excluded.full_name, role = 'admin', is_active = true, updated_at = now(); -- DEVOLVER A USUARIO NORMAL: -- delete from public.glm_hub_authorized_users -- where email = 'usuario@gomezleemarketing.com'; -- BLOQUEAR USUARIO: -- insert into public.glm_hub_authorized_users (email, full_name, role, is_active) -- values ('usuario@gomezleemarketing.com', 'Nombre del usuario', 'member', false) -- on conflict (email) do update -- set full_name = excluded.full_name, role = 'member', is_active = false, updated_at = now(); -- DESBLOQUEAR USUARIO: -- delete from public.glm_hub_authorized_users -- where email = 'usuario@gomezleemarketing.com' -- and role = 'member';