132 lines
4.5 KiB
PL/PgSQL
132 lines
4.5 KiB
PL/PgSQL
|
|
-- Criar enum para níveis de permissão
|
|
CREATE TYPE public.permission_level AS ENUM (
|
|
'can_admin',
|
|
'can_create_update_delete',
|
|
'can_create_only',
|
|
'can_view_only',
|
|
'no_access'
|
|
);
|
|
|
|
-- Criar tabela para permissões específicas por usuário e recurso
|
|
CREATE TABLE public.user_interface_permissions (
|
|
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
resource_key TEXT NOT NULL REFERENCES public.interface_resources(resource_key) ON DELETE CASCADE,
|
|
permission public.permission_level NOT NULL DEFAULT 'no_access',
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
PRIMARY KEY (user_id, resource_key)
|
|
);
|
|
|
|
-- Criar índice para busca por resource_key
|
|
CREATE INDEX idx_user_interface_permissions_resource_key ON public.user_interface_permissions(resource_key);
|
|
|
|
-- Habilitar RLS
|
|
ALTER TABLE public.user_interface_permissions ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- Política para SELECT: usuário pode ver suas próprias permissões, admin pode ver todas
|
|
CREATE POLICY "Users can view own permissions, admins can view all"
|
|
ON public.user_interface_permissions
|
|
FOR SELECT
|
|
USING (
|
|
auth.uid() = user_id OR
|
|
public.has_role(auth.uid(), 'admin'::app_role)
|
|
);
|
|
|
|
-- Política para INSERT/UPDATE/DELETE: apenas admin
|
|
CREATE POLICY "Only admins can manage user permissions"
|
|
ON public.user_interface_permissions
|
|
FOR ALL
|
|
USING (public.has_role(auth.uid(), 'admin'::app_role))
|
|
WITH CHECK (public.has_role(auth.uid(), 'admin'::app_role));
|
|
|
|
-- Trigger para atualizar updated_at
|
|
CREATE OR REPLACE FUNCTION public.update_user_permissions_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = now();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER update_user_interface_permissions_updated_at
|
|
BEFORE UPDATE ON public.user_interface_permissions
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION public.update_user_permissions_updated_at();
|
|
|
|
-- Função RPC para obter permissão efetiva de um usuário para um recurso específico
|
|
CREATE OR REPLACE FUNCTION public.get_effective_permission_for_resource(
|
|
_user_id UUID,
|
|
_resource_key TEXT
|
|
)
|
|
RETURNS public.permission_level
|
|
LANGUAGE plpgsql
|
|
SECURITY DEFINER
|
|
AS $$
|
|
DECLARE
|
|
user_permission public.permission_level;
|
|
user_privileges RECORD;
|
|
BEGIN
|
|
-- Se é admin, sempre retorna can_admin
|
|
IF public.has_role(_user_id, 'admin'::app_role) THEN
|
|
RETURN 'can_admin'::permission_level;
|
|
END IF;
|
|
|
|
-- Verificar se existe override específico para este usuário e recurso
|
|
SELECT permission INTO user_permission
|
|
FROM public.user_interface_permissions
|
|
WHERE user_id = _user_id AND resource_key = _resource_key;
|
|
|
|
-- Se existe override, retornar ele
|
|
IF user_permission IS NOT NULL THEN
|
|
RETURN user_permission;
|
|
END IF;
|
|
|
|
-- Caso contrário, usar permissões funcionais do privilégio do usuário
|
|
SELECT p.permissions INTO user_privileges
|
|
FROM public.profiles pr
|
|
JOIN public.privileges p ON pr.privilege_id = p.id
|
|
WHERE pr.id = _user_id;
|
|
|
|
-- Se não tem privilégio definido, sem acesso
|
|
IF user_privileges.permissions IS NULL THEN
|
|
RETURN 'no_access'::permission_level;
|
|
END IF;
|
|
|
|
-- Converter permissões funcionais para permission_level (maior nível disponível)
|
|
IF (user_privileges.permissions->>'can_admin')::boolean = true THEN
|
|
RETURN 'can_admin'::permission_level;
|
|
ELSIF (user_privileges.permissions->>'can_create_update_delete')::boolean = true THEN
|
|
RETURN 'can_create_update_delete'::permission_level;
|
|
ELSIF (user_privileges.permissions->>'can_create_only')::boolean = true THEN
|
|
RETURN 'can_create_only'::permission_level;
|
|
ELSIF (user_privileges.permissions->>'can_view_only')::boolean = true THEN
|
|
RETURN 'can_view_only'::permission_level;
|
|
ELSE
|
|
RETURN 'no_access'::permission_level;
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
-- Função RPC para obter todas as permissões efetivas de um usuário
|
|
CREATE OR REPLACE FUNCTION public.get_effective_permissions_for_user(_user_id UUID)
|
|
RETURNS TABLE(resource_key TEXT, permission public.permission_level)
|
|
LANGUAGE plpgsql
|
|
SECURITY DEFINER
|
|
AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT
|
|
ir.resource_key,
|
|
public.get_effective_permission_for_resource(_user_id, ir.resource_key) as permission
|
|
FROM public.interface_resources ir
|
|
ORDER BY ir.resource_key;
|
|
END;
|
|
$$;
|
|
|
|
-- Habilitar realtime para a tabela user_interface_permissions
|
|
ALTER PUBLICATION supabase_realtime ADD TABLE public.user_interface_permissions;
|
|
|
|
-- Definir REPLICA IDENTITY FULL para payloads completos no realtime
|
|
ALTER TABLE public.user_interface_permissions REPLICA IDENTITY FULL;
|