CREATE SCHEMA IF NOT EXISTS private; REVOKE ALL ON SCHEMA private FROM PUBLIC, anon, authenticated; GRANT USAGE ON SCHEMA private TO postgres, service_role; CREATE OR REPLACE FUNCTION private.has_role(_user_id uuid, _role public.app_role) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$ SELECT EXISTS (SELECT 1 FROM public.papeis_usuario WHERE user_id = _user_id AND role = _role) $$; CREATE OR REPLACE FUNCTION private.is_aprovado(_user_id uuid) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$ SELECT EXISTS (SELECT 1 FROM public.perfis WHERE id = _user_id AND aprovado = true) $$; DROP POLICY "Admins veem todos os papeis" ON public.papeis_usuario; CREATE POLICY "Admins veem todos os papeis" ON public.papeis_usuario FOR SELECT TO authenticated USING (private.has_role(auth.uid(), 'admin'::public.app_role)); DROP POLICY "Admins atualizam perfis" ON public.perfis; CREATE POLICY "Admins atualizam perfis" ON public.perfis FOR UPDATE TO authenticated USING (private.has_role(auth.uid(), 'admin'::public.app_role)) WITH CHECK (private.has_role(auth.uid(), 'admin'::public.app_role)); DROP POLICY "Admins veem todos os perfis" ON public.perfis; CREATE POLICY "Admins veem todos os perfis" ON public.perfis FOR SELECT TO authenticated USING (private.has_role(auth.uid(), 'admin'::public.app_role)); DROP POLICY "Aprovados atualizam coletas" ON public.coletas; CREATE POLICY "Aprovados atualizam coletas" ON public.coletas FOR UPDATE TO authenticated USING (private.is_aprovado(auth.uid())) WITH CHECK (private.is_aprovado(auth.uid())); DROP POLICY "Aprovados criam coletas" ON public.coletas; CREATE POLICY "Aprovados criam coletas" ON public.coletas FOR INSERT TO authenticated WITH CHECK (private.is_aprovado(auth.uid())); DROP POLICY "Aprovados veem coletas" ON public.coletas; CREATE POLICY "Aprovados veem coletas" ON public.coletas FOR SELECT TO authenticated USING (private.is_aprovado(auth.uid())); DROP FUNCTION IF EXISTS public.has_role(uuid, public.app_role); DROP FUNCTION IF EXISTS public.is_aprovado(uuid); CREATE OR REPLACE FUNCTION private.registrar_perfil_para(_uid uuid, _email text) RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_primeiro boolean; BEGIN IF EXISTS (SELECT 1 FROM public.perfis WHERE id = _uid) THEN RETURN; END IF; SELECT NOT EXISTS (SELECT 1 FROM public.perfis) INTO v_primeiro; INSERT INTO public.perfis (id, email, nome, aprovado) VALUES (_uid, coalesce(_email, ''), split_part(coalesce(_email, ''), '@', 1), v_primeiro); IF v_primeiro THEN INSERT INTO public.papeis_usuario (user_id, role) VALUES (_uid, 'admin') ON CONFLICT DO NOTHING; END IF; END; $$; CREATE OR REPLACE FUNCTION private.on_auth_user_created() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ BEGIN PERFORM private.registrar_perfil_para(NEW.id, NEW.email); RETURN NEW; END; $$; DROP FUNCTION IF EXISTS public.registrar_perfil();