# app/controllers/admin/perfis_acesso_controller.rb # # CRUD dos perfis de acesso. É aqui que o ADM decide o que cada função enxerga, # sem depender de deploy: o catálogo do que pode ser marcado é código # (Permissao::TODAS), a escolha é dado (PerfilAcesso#permissoes). module Admin class PerfisAcessoController < ApplicationController include Auditavel before_action :set_perfil, only: %i[edit update destroy] def index authorize PerfilAcesso @perfis = policy_scope(PerfilAcesso).ordenados.includes(:users) end def new @perfil = PerfilAcesso.new(ativo: true, permissoes: []) authorize @perfil end def create @perfil = PerfilAcesso.new(perfil_params) authorize @perfil if @perfil.save auditar!(:criar, @perfil, dados_novos: { nome: @perfil.nome, permissoes: @perfil.permissoes }) redirect_to admin_perfis_path, notice: "Perfil #{@perfil.nome} criado." else render :new, status: :unprocessable_entity end end def edit; end def update anteriores = @perfil.permissoes # Ordem importa: aplicamos os valores em memória para a trava conferir o # que o ADM ESTÁ salvando, não o que está no banco. @perfil.assign_attributes(perfil_params) if travaria_o_sistema? @perfil.errors.add(:base, mensagem_da_trava) return render(:edit, status: :unprocessable_entity) end if @perfil.save auditar!(:editar, @perfil, dados_anteriores: { permissoes: anteriores }, dados_novos: { permissoes: @perfil.permissoes, ativo: @perfil.ativo }) redirect_to admin_perfis_path, notice: "Perfil #{@perfil.nome} atualizado." else render :edit, status: :unprocessable_entity end end def destroy unless @perfil.apagavel? return redirect_to(admin_perfis_path, alert: motivo_para_nao_apagar) end @perfil.destroy auditar!(:excluir, @perfil, dados_anteriores: { nome: @perfil.nome }) redirect_to admin_perfis_path, notice: 'Perfil excluído.' end private def set_perfil @perfil = PerfilAcesso.find(params[:id]) authorize @perfil end def perfil_params dados = params.require(:perfil_acesso).permit(:nome, :descricao, :ativo, permissoes: []) # O form manda um campo vazio para o caso de NENHUMA caixa marcada (senão o # parâmetro some e "desmarcar tudo" viraria "não mexer em nada"). dados[:permissoes] = Permissao.filtrar(dados[:permissoes]) dados end # ── Trava do último administrador ──────────────────────── # Mesma regra da tela de usuários (User.administradores_de_acesso): salvar um # perfil que perde `admin.perfis`/`admin.usuarios_gerenciar` (ou é desativado) # não pode deixar o sistema sem quem conserte. def travaria_o_sistema? return false if @perfil.administra_acesso? # continua podendo: nada a checar return false unless @perfil.users.ativos.exists? # perfil vazio não tira acesso de ninguém # Quem está NESTE perfil perderá o acesso; sobra alguém fora dele? # Usuário sem perfil conta: cai no padrão do papel (admin legado administra). restantes = User.administradores_de_acesso.reject { |u| u.perfil_acesso_id == @perfil.id } restantes.empty? end def mensagem_da_trava 'Esta alteração deixaria o sistema sem nenhum usuário ativo capaz de gerenciar ' \ 'perfis e usuários. Garanta que outra pessoa mantenha esse acesso antes de salvar.' end def motivo_para_nao_apagar if @perfil.sistema? 'Perfis que vêm com o sistema não podem ser excluídos — desative-o ou edite as permissões.' else "Este perfil está em uso por #{@perfil.users.count} usuário(s). Mova essas pessoas para outro perfil antes de excluir." end end end end