# Estratégia de Controle de Permissões Granular ## Visão Geral Esta documentação descreve a estratégia implementada para controle de permissões granular no sistema, permitindo que usuários vejam apenas dados e elementos para os quais têm autorização, sem quebrar templates ou causar erros. ## Arquitetura da Solução ### 1. Context Processors **Arquivo**: `functions/template_helpers.py` Os context processors disponibilizam automaticamente as permissões do usuário em todos os templates: ```python # Disponível em todos os templates user_can('permission_name') # Verifica permissão específica user_has_role('role_name') # Verifica role específica is_admin # Booleano se é admin current_user_data # Dados completos do usuário ``` ### 2. Template Filters Filtros Jinja2 para uso direto nos templates: ```jinja2 {{ 'view_cell_data' | has_permission }} {{ militantes | safe_data('view_cell_data', []) }} {{ 'militante' | can_manage }} ``` ### 3. Safe Data Controllers Decorators que retornam dados vazios em caso de falta de permissão: ```python @safe_data_controller(Permission.VIEW_CELL_DATA, empty_data={'militantes': []}) def listar(): # Lógica normal do controller return render_template('template.html', militantes=militantes) ``` ### 4. Template Macros Componentes reutilizáveis para elementos condicionais: ```jinja2 {% from 'components/permission_wrapper.html' import permission_button %} {{ permission_button('create_cell_member', url_for('militante.novo'), 'Novo Militante') }} ``` ## Implementação por Camadas ### Camada 1: Controllers (Backend) ```python # Filtragem de dados baseada em permissões if current_user.is_admin: # Admin vê todos os dados militantes = query.all() elif current_user.has_permission(Permission.VIEW_CR_REPORTS): # CR vê apenas do seu CR militantes = query.filter(cr_id=current_user.cr_id).all() else: # Sem permissão - lista vazia militantes = [] ``` ### Camada 2: Templates (Frontend) ```jinja2 {% if user_can('view_cell_data') %} {% endif %} {% if user_can('view_cell_data') %} {% if militantes %} {% else %}
Nenhum dado disponível
{% endif %} {% else %}
Sem permissão para visualizar
{% endif %} ``` ### Camada 3: JavaScript (Interação) ```javascript // Verificações no frontend if (userPermissions.includes('manage_cell_members')) { // Habilitar funcionalidades de edição enableEditFeatures(); } ``` ## Níveis de Permissão ### 1. Visualização de Dados - `view_own_data`: Apenas próprios dados - `view_cell_data`: Dados da célula - `view_sector_reports`: Dados do setor - `view_cr_reports`: Dados do CR - `view_cc_reports`: Dados nacionais ### 2. Gerenciamento - `manage_cell_members`: Gerenciar membros da célula - `manage_sector_cells`: Gerenciar células do setor - `create_cell_member`: Criar novos membros - `register_cell_payment`: Registrar pagamentos ### 3. Administração - `system_config`: Configurações do sistema - `manage_cc_crs`: Gerenciar CRs - `create_cc_cr`: Criar novos CRs ## Regras Especiais de Permissão ### 1. Administrador (Admin) - **Acesso Total**: Tem todas as permissões do sistema - **Bypass de Verificações**: Sempre retorna `true` para qualquer verificação de permissão - **Acesso a Configurações**: Pode configurar o sistema e gerenciar usuários ### 2. Tesoureiro - **Regra Especial**: Tesoureiro pode fazer tudo que o secretário da instância pode fazer - **Permissões Automáticas**: Quando um militante tem responsabilidade de `TESOUREIRO`, automaticamente recebe: - `view_cell_data`: Visualizar dados da célula - `manage_cell_members`: Gerenciar membros da célula - `create_cell_member`: Criar novos membros - `view_cell_reports`: Visualizar relatórios da célula - `manage_cell_reports`: Gerenciar relatórios da célula - `register_cell_payment`: Registrar pagamentos da célula ### 3. Hierarquia de Instâncias - **Célula** → **Setor** → **CR** → **CC** - Usuários de níveis superiores têm acesso aos dados dos níveis inferiores - Secretários podem gerenciar todas as instâncias de seu nível e abaixo ## Padrões de Uso ### 1. Menus Condicionais ```jinja2 {% if user_can('view_cell_data') %} {% endif %} ``` ### 2. Botões Condicionais ```jinja2 {% if user_can('create_cell_member') %} Novo Militante {% endif %} ``` ### 3. Dados Filtrados ```jinja2 {% if user_can('view_cell_data') %} {% if militantes %}
{% else %}
Nenhum militante encontrado
{% endif %} {% else %}
Você não tem permissão para visualizar estes dados
{% endif %} ``` ### 4. Formulários Condicionais ```jinja2 {% if user_can('create_cell_member') %}
{% else %}
Você não tem permissão para criar militantes
{% endif %} ``` ## Tratamento de Erros ### 1. Dados Não Encontrados ```jinja2 {% if user_can('view_cell_data') %} {% if data %} {% else %}
Nenhum registro encontrado
{% endif %} {% endif %} ``` ### 2. Permissão Negada ```jinja2 {% if not user_can('required_permission') %}
Você não tem permissão para acessar esta funcionalidade
{% endif %} ``` ### 3. Fallbacks Graceful ```python # Controller com fallback @safe_data_controller('view_cell_data', empty_data={'militantes': []}) def listar(): # Se não tiver permissão, retorna lista vazia # Template não quebra, apenas não mostra dados pass ``` ## Vantagens da Estratégia ### 1. **Segurança por Camadas** - Verificação no backend (controllers) - Verificação no frontend (templates) - Verificação no JavaScript (interação) ### 2. **Graceful Degradation** - Templates nunca quebram - Dados vazios em vez de erros - Mensagens informativas para usuário ### 3. **Flexibilidade** - Permissões granulares - Fácil de estender - Reutilização de componentes ### 4. **Manutenibilidade** - Lógica centralizada - Padrões consistentes - Fácil debugging ### 5. **UX Melhorada** - Interface adapta-se às permissões - Sem elementos inacessíveis visíveis - Feedback claro sobre limitações ## Exemplo Completo de Implementação ### Controller ```python @militante_bp.route("/militantes") @require_login @safe_data_controller(Permission.VIEW_CELL_DATA, empty_data={'militantes': []}) def listar(): # Filtragem baseada em permissões if current_user.is_admin: militantes = query.all() elif current_user.has_permission(Permission.VIEW_CELL_DATA): militantes = query.filter(celula_id=current_user.celula_id).all() else: militantes = [] return render_template('militantes.html', militantes=militantes) ``` ### Template ```jinja2 {% extends "base.html" %} {% block content %}

Militantes

{% if user_can('create_cell_member') %} Novo Militante {% endif %}
{% if user_can('view_cell_data') %} {% if militantes %} {% if user_can('manage_cell_members') %} {% endif %} {% for militante in militantes %} {% if user_can('manage_cell_members') %} {% endif %} {% endfor %}
Nome EmailAções
{{ militante.nome }} {{ militante.email }}
{% else %}
Nenhum militante encontrado
{% endif %} {% else %}
Você não tem permissão para visualizar militantes
{% endif %} {% endblock %} ``` ## Conclusão Esta estratégia garante que: 1. **Nunca há erros de template** - dados sempre estão disponíveis (mesmo que vazios) 2. **Segurança é mantida** - usuários só veem o que podem 3. **UX é preservada** - interface clara sobre limitações 4. **Código é limpo** - padrões reutilizáveis e consistentes 5. **Manutenção é fácil** - lógica centralizada e bem documentada 6. **Tesoureiros têm poder adequado** - podem fazer tudo que secretários fazem A implementação permite desenvolvimento ágil sem comprometer segurança ou experiência do usuário.