--- name: perfex-permissions description: Perfex CRM permissions system. staff_can(), register_staff_capabilities(), access control. Based on official documentation only. Use when user mentions "perfex permissions", "staff_can", "access control", "capabilities perfex". author: Descomplicar® Crescimento Digital version: 1.0.0 quality_score: 70 user_invocable: true desk_task: null --- # /perfex-permissions - Permissões Perfex CRM Sistema de permissões e controlo de acesso. **Zero assumptions, zero hallucinations** - apenas documentação oficial. --- ## Documentação Base - [Staff Capabilities and Access](https://help.perfexcrm.com/staff-capabilities-and-access/) - [Roles](https://help.perfexcrm.com/roles/) --- ## Conceitos Fundamentais | Conceito | Descrição | |----------|-----------| | **Feature** | Área funcional (invoices, projects, meu_modulo) | | **Capability** | Permissão específica (view, create, edit, delete) | | **Role** | Conjunto de permissões pré-definido | --- ## Registar Permissões do Módulo ### No Init File ```php hooks()->add_action('admin_init', 'meu_modulo_register_permissions'); function meu_modulo_register_permissions() { $capabilities = []; $capabilities['capabilities'] = [ 'view' => _l('permission_view'), // Ver 'create' => _l('permission_create'), // Criar 'edit' => _l('permission_edit'), // Editar 'delete' => _l('permission_delete'), // Apagar ]; register_staff_capabilities( 'meu_modulo', // Feature ID (único) $capabilities, // Array de capabilities _l('meu_modulo_title') // Nome do módulo (mostrado em Settings) ); } ``` ### Parâmetros register_staff_capabilities() | Parâmetro | Tipo | Descrição | |-----------|------|-----------| | `$feature` | string | ID único da feature | | `$capabilities` | array | Array com key 'capabilities' | | `$name` | string | Nome mostrado na UI | --- ## Verificar Permissões: staff_can() ### Sintaxe ```php staff_can($capability, $feature = null, $staff_id = ''); ``` ### Parâmetros | Parâmetro | Tipo | Descrição | |-----------|------|-----------| | `$capability` | string | Nome da capability (view, create, etc.) | | `$feature` | string | Feature ID (recomendado SEMPRE passar) | | `$staff_id` | int | ID do staff (default: staff logado) | ### Retorno - `true` - Staff tem permissão - `false` - Staff não tem permissão **NOTA:** Administradores SEMPRE retornam `true` (bypass total). --- ## Exemplos de Uso ### No Controller ```php class Meu_modulo extends AdminController { public function index() { // Verificar permissão de ver if (!staff_can('view', 'meu_modulo')) { access_denied('meu_modulo'); } // ... código } public function create() { // Verificar permissão de criar if (!staff_can('create', 'meu_modulo')) { access_denied('meu_modulo'); } // ... código } public function edit($id) { // Verificar permissão de editar if (!staff_can('edit', 'meu_modulo')) { access_denied('meu_modulo'); } // ... código } public function delete($id) { // Verificar permissão de apagar if (!staff_can('delete', 'meu_modulo')) { access_denied('meu_modulo'); } // ... código } } ``` ### Na View ```php ``` ### No Menu ```php function meu_modulo_init_menu() { // Só mostrar menu se tem permissão if (!staff_can('view', 'meu_modulo')) { return; } $CI = &get_instance(); $CI->app_menu->add_sidebar_menu_item('meu-modulo', [ 'name' => _l('meu_modulo'), 'href' => admin_url('meu_modulo'), 'position' => 25, 'icon' => 'fa fa-cube', ]); } ``` --- ## Capabilities Padrão ### Recomendadas para CRUD | Capability | Descrição | Uso | |------------|-----------|-----| | `view` | Ver registos | Listar, ver detalhes | | `create` | Criar novos | Formulário de criação | | `edit` | Editar existentes | Formulário de edição | | `delete` | Apagar registos | Botão de eliminar | ### Adicionar Capabilities Custom ```php $capabilities['capabilities'] = [ // CRUD básico 'view' => _l('permission_view'), 'create' => _l('permission_create'), 'edit' => _l('permission_edit'), 'delete' => _l('permission_delete'), // Custom 'export' => _l('permission_export'), // Exportar dados 'import' => _l('permission_import'), // Importar dados 'send_email' => _l('permission_send_email'), // Enviar emails 'view_all' => _l('permission_view_all'), // Ver todos (não só próprios) 'approve' => _l('permission_approve'), // Aprovar items ]; ``` --- ## Adicionar Permissões a Features Existentes Para adicionar capabilities a módulos do core (invoices, projects, etc.): ```php hooks()->add_action('admin_init', 'meu_modulo_extend_permissions'); function meu_modulo_extend_permissions() { $capabilities = []; $capabilities['capabilities'] = [ 'meu_modulo_custom_action' => _l('meu_modulo_custom_action_label'), ]; // Adicionar à feature "invoices" register_staff_capabilities('invoices', $capabilities); } ``` **Uso:** ```php if (staff_can('meu_modulo_custom_action', 'invoices')) { // Acção custom em facturas } ``` --- ## Verificar Administrador ```php // Verificar se é admin (tem todas as permissões) if (is_admin()) { // Utilizador é administrador } // Verificar se é admin específico (ID 1) if (is_admin(1)) { // Staff com ID 1 é admin } ``` --- ## Funções Auxiliares ### Acesso Negado ```php // Redireciona com mensagem de acesso negado access_denied('meu_modulo'); ``` ### Verificar Staff Logado ```php // ID do staff actual $staff_id = get_staff_user_id(); // Verificar se está logado if (is_staff_logged_in()) { // Staff autenticado } ``` ### Verificar Permissão de Outro Staff ```php // Verificar se staff ID 5 pode editar $can_edit = staff_can('edit', 'meu_modulo', 5); ``` --- ## Exemplo Completo ### Init File ```php add_action('admin_init', 'inventario_register_permissions'); hooks()->add_action('admin_init', 'inventario_init_menu'); function inventario_register_permissions() { $capabilities = [ 'capabilities' => [ 'view' => _l('permission_view'), 'create' => _l('permission_create'), 'edit' => _l('permission_edit'), 'delete' => _l('permission_delete'), 'export' => _l('inventory_permission_export'), 'adjust' => _l('inventory_permission_adjust'), // Ajustar stock 'view_costs' => _l('inventory_permission_view_costs'), // Ver custos ], ]; register_staff_capabilities( 'inventario', $capabilities, _l('inventory_module') ); } function inventario_init_menu() { if (!staff_can('view', 'inventario')) { return; } $CI = &get_instance(); $CI->app_menu->add_sidebar_menu_item('inventario', [ 'name' => _l('inventory'), 'collapse' => true, 'position' => 22, 'icon' => 'fa fa-cubes', ]); $CI->app_menu->add_sidebar_children_item('inventario', [ 'slug' => 'inventario-lista', 'name' => _l('products'), 'href' => admin_url('inventario'), 'position' => 1, 'icon' => 'fa fa-list', ]); if (staff_can('adjust', 'inventario')) { $CI->app_menu->add_sidebar_children_item('inventario', [ 'slug' => 'inventario-ajustes', 'name' => _l('adjustments'), 'href' => admin_url('inventario/adjustments'), 'position' => 2, 'icon' => 'fa fa-exchange', ]); } if (staff_can('export', 'inventario')) { $CI->app_menu->add_sidebar_children_item('inventario', [ 'slug' => 'inventario-export', 'name' => _l('export'), 'href' => admin_url('inventario/export'), 'position' => 3, 'icon' => 'fa fa-download', ]); } } ``` ### Controller ```php load->model('inventario/inventario_model'); } public function index() { if (!staff_can('view', 'inventario')) { access_denied('inventario'); } $data['products'] = $this->inventario_model->get_all(); // Se pode ver custos, incluir if (staff_can('view_costs', 'inventario')) { $data['show_costs'] = true; } $this->load->view('inventario/index', $data); } public function adjustments() { if (!staff_can('adjust', 'inventario')) { access_denied('inventario'); } // ... lógica de ajustes } public function export() { if (!staff_can('export', 'inventario')) { access_denied('inventario'); } // ... lógica de exportação } } ``` --- ## Anti-Patterns (NUNCA FAZER) | Anti-Pattern | Risco | Alternativa | |--------------|-------|-------------| | Não verificar permissões no controller | Acesso não autorizado | `staff_can()` sempre | | Confiar apenas na UI | Bypass via URL | Verificar em backend | | Feature ID duplicado | Conflitos | Prefixar com nome módulo | | Capability sem _l() | Não traduzível | Usar traduções | | Assumir que view esconde acção | Vulnerável | Verificar em ambos | --- ## Checklist Permissões ``` 1. [ ] register_staff_capabilities no init file 2. [ ] Feature ID único 3. [ ] Capabilities com traduções (_l) 4. [ ] staff_can() em TODOS os métodos do controller 5. [ ] staff_can() nas views para UI condicional 6. [ ] staff_can() antes de mostrar menus 7. [ ] access_denied() para rejeitar acesso 8. [ ] Testado com utilizador não-admin ``` --- **Versão:** 1.0.0 | **Autor:** Descomplicar® **Fonte:** help.perfexcrm.com/staff-capabilities-and-access