-- Perfis CREATE TABLE public.perfis ( id uuid PRIMARY KEY, email text NOT NULL, aprovado boolean NOT NULL DEFAULT false, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); GRANT SELECT, INSERT, UPDATE ON public.perfis TO authenticated; GRANT ALL ON public.perfis TO service_role; ALTER TABLE public.perfis ENABLE ROW LEVEL SECURITY; -- Papeis CREATE TYPE public.app_role AS ENUM ('admin', 'user'); CREATE TABLE public.papeis_usuario ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), user_id uuid NOT NULL, role public.app_role NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), UNIQUE (user_id, role) ); GRANT SELECT ON public.papeis_usuario TO authenticated; GRANT ALL ON public.papeis_usuario TO service_role; ALTER TABLE public.papeis_usuario ENABLE ROW LEVEL SECURITY; CREATE OR REPLACE FUNCTION public.has_role(_user_id uuid, _role public.app_role) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path = public AS $$ SELECT EXISTS ( SELECT 1 FROM public.papeis_usuario WHERE user_id = _user_id AND role = _role ) $$; CREATE OR REPLACE FUNCTION public.is_aprovado(_user_id uuid) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path = public AS $$ SELECT EXISTS ( SELECT 1 FROM public.perfis WHERE id = _user_id AND aprovado = true ) $$; -- Policies perfis CREATE POLICY "Ver proprio perfil" ON public.perfis FOR SELECT TO authenticated USING (id = auth.uid()); CREATE POLICY "Admins veem todos os perfis" ON public.perfis FOR SELECT TO authenticated USING (public.has_role(auth.uid(), 'admin')); CREATE POLICY "Criar proprio perfil" ON public.perfis FOR INSERT TO authenticated WITH CHECK (id = auth.uid()); CREATE POLICY "Admins atualizam perfis" ON public.perfis FOR UPDATE TO authenticated USING (public.has_role(auth.uid(), 'admin')) WITH CHECK (public.has_role(auth.uid(), 'admin')); -- Policies papeis CREATE POLICY "Ver proprios papeis" ON public.papeis_usuario FOR SELECT TO authenticated USING (user_id = auth.uid()); CREATE POLICY "Admins veem todos os papeis" ON public.papeis_usuario FOR SELECT TO authenticated USING (public.has_role(auth.uid(), 'admin')); -- Registro de perfil: primeiro usuario vira admin aprovado CREATE OR REPLACE FUNCTION public.registrar_perfil() RETURNS public.perfis LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$ DECLARE v_uid uuid := auth.uid(); v_email text; v_primeiro boolean; v_perfil public.perfis; BEGIN IF v_uid IS NULL THEN RAISE EXCEPTION 'Nao autenticado'; END IF; SELECT * INTO v_perfil FROM public.perfis WHERE id = v_uid; IF FOUND THEN RETURN v_perfil; END IF; SELECT email INTO v_email FROM auth.users WHERE id = v_uid; SELECT NOT EXISTS (SELECT 1 FROM public.perfis) INTO v_primeiro; INSERT INTO public.perfis (id, email, aprovado) VALUES (v_uid, coalesce(v_email, ''), v_primeiro) RETURNING * INTO v_perfil; IF v_primeiro THEN INSERT INTO public.papeis_usuario (user_id, role) VALUES (v_uid, 'admin') ON CONFLICT DO NOTHING; END IF; RETURN v_perfil; END; $$; GRANT EXECUTE ON FUNCTION public.registrar_perfil() TO authenticated; CREATE OR REPLACE FUNCTION public.set_updated_at() RETURNS TRIGGER LANGUAGE plpgsql SET search_path = public AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$; CREATE TRIGGER perfis_updated_at BEFORE UPDATE ON public.perfis FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- Coletas: apenas usuarios logados e aprovados DROP POLICY IF EXISTS "Coletas sao visiveis publicamente" ON public.coletas; DROP POLICY IF EXISTS "Qualquer um pode atualizar coleta" ON public.coletas; DROP POLICY IF EXISTS "Qualquer um pode criar coleta" ON public.coletas; REVOKE ALL ON public.coletas FROM anon; GRANT SELECT, INSERT, UPDATE ON public.coletas TO authenticated; GRANT ALL ON public.coletas TO service_role; CREATE POLICY "Aprovados veem coletas" ON public.coletas FOR SELECT TO authenticated USING (public.is_aprovado(auth.uid())); CREATE POLICY "Aprovados criam coletas" ON public.coletas FOR INSERT TO authenticated WITH CHECK (public.is_aprovado(auth.uid())); CREATE POLICY "Aprovados atualizam coletas" ON public.coletas FOR UPDATE TO authenticated USING (public.is_aprovado(auth.uid())) WITH CHECK (public.is_aprovado(auth.uid()));