mirror of
https://gitlab.unicamp.br/infimecc_drupal11_modules/ldap_groups_sync.git
synced 2026-03-08 01:17:41 -03:00
Inicializa módulo base ldap_groups_sync
Cria super-módulo com infraestrutura compartilhada de regras de acesso para os módulos de sincronização LDAP de grupos. - GroupAccessRulesService: serviço parametrizável por config name - AccessRulesFormBase: listagem/remoção de regras (classe abstrata) - AccessRuleFormBase: formulário modal de criação/edição (classe abstrata) - Sub-módulos ldap_departments_sync e ldap_research_groups_sync refatorados para estender as classes base com subclasses mínimas - Traduções pt-br centralizadas em ldap_groups_sync.pt-br.po Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
99
README.md
Normal file
99
README.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# LDAP Groups Sync
|
||||
|
||||
Módulo base que provê a infraestrutura compartilhada de **regras de acesso** para os módulos de sincronização LDAP de grupos.
|
||||
|
||||
Não realiza sincronização por si só — funciona como biblioteca de classes abstratas instanciada pelos sub-módulos que ficam dentro deste repositório.
|
||||
|
||||
## Sub-módulos incluídos
|
||||
|
||||
| Módulo | Tipo de grupo | Rota de configuração |
|
||||
|---|---|---|
|
||||
| `ldap_departments_sync` | `departments` | `/admin/config/local-modules/ldap-departments-sync` |
|
||||
| `ldap_research_groups_sync` | `research_group` | `/admin/config/local-modules/ldap-research-groups-sync` |
|
||||
|
||||
## Estrutura
|
||||
|
||||
```
|
||||
ldap_groups_sync/
|
||||
├── src/
|
||||
│ ├── GroupAccessRulesService.php # serviço de verificação de acesso
|
||||
│ └── Form/
|
||||
│ ├── AccessRulesFormBase.php # listagem e remoção de regras
|
||||
│ └── AccessRuleFormBase.php # criação/edição de regra (modal)
|
||||
├── translations/
|
||||
│ └── ldap_groups_sync.pt-br.po
|
||||
│
|
||||
├── ldap_departments_sync/ # sub-módulo
|
||||
└── ldap_research_groups_sync/ # sub-módulo
|
||||
```
|
||||
|
||||
## Regras de acesso
|
||||
|
||||
A infraestrutura de regras de acesso permite configurar, por interface, quais operações (`create`, `update`, `delete`, `view`) cada entidade permite — e a quais membros de grupo com quais papéis.
|
||||
|
||||
Cada regra define:
|
||||
|
||||
- **Tipo de entidade / bundle** ao qual se aplica
|
||||
- **Operações** controladas
|
||||
- **Modo**: _Restritivo_ (nega quem não satisfaz) ou _Aditivo_ (só concede, sem negar)
|
||||
- **Requisitos de membro**: um ou mais pares (grupo + papéis requeridos)
|
||||
- **Condições de campo** opcionais avaliadas sobre a entidade existente (para `update`/`delete`/`view`)
|
||||
|
||||
## Como adicionar um novo sub-módulo
|
||||
|
||||
1. Crie o diretório do módulo dentro de `ldap_groups_sync/`.
|
||||
|
||||
2. Declare `ldap_groups_sync:ldap_groups_sync` como dependência no `.info.yml`.
|
||||
|
||||
3. No `.services.yml`, use `GroupAccessRulesService` com o config name como terceiro argumento:
|
||||
|
||||
```yaml
|
||||
meu_modulo.access_rules:
|
||||
class: Drupal\ldap_groups_sync\GroupAccessRulesService
|
||||
arguments: ['@config.factory', '@entity_type.manager', 'meu_modulo.settings']
|
||||
```
|
||||
|
||||
4. Crie `src/Form/AccessRulesForm.php` estendendo `AccessRulesFormBase`:
|
||||
|
||||
```php
|
||||
namespace Drupal\meu_modulo\Form;
|
||||
|
||||
use Drupal\ldap_groups_sync\Form\AccessRulesFormBase;
|
||||
|
||||
class AccessRulesForm extends AccessRulesFormBase {
|
||||
protected function getConfigName(): string { return 'meu_modulo.settings'; }
|
||||
public function getFormId(): string { return 'meu_modulo_access_rules_form'; }
|
||||
protected function getAccessRuleFormRoute(): string { return 'meu_modulo.access_rule_form'; }
|
||||
}
|
||||
```
|
||||
|
||||
5. Crie `src/Form/AccessRuleForm.php` estendendo `AccessRuleFormBase`:
|
||||
|
||||
```php
|
||||
namespace Drupal\meu_modulo\Form;
|
||||
|
||||
use Drupal\ldap_groups_sync\Form\AccessRuleFormBase;
|
||||
|
||||
class AccessRuleForm extends AccessRuleFormBase {
|
||||
protected function getConfigName(): string { return 'meu_modulo.settings'; }
|
||||
public function getFormId(): string { return 'meu_modulo_access_rule_form'; }
|
||||
protected function getAccessRulesRoute(): string { return 'meu_modulo.access_rules'; }
|
||||
protected function getDefaultGroupTypeId(): string { return 'meu_group_type'; }
|
||||
}
|
||||
```
|
||||
|
||||
## Dependências
|
||||
|
||||
- `drupal:options`
|
||||
- `drupal:telephone`
|
||||
- `group:group`
|
||||
- `ldap:ldap_servers`
|
||||
- `site_tools`
|
||||
|
||||
## Licença
|
||||
|
||||
GPL-2.0-or-later
|
||||
|
||||
## Autor
|
||||
|
||||
Desenvolvido para o IME - UNICAMP
|
||||
46
ldap_departments_sync/CHANGELOG.md
Normal file
46
ldap_departments_sync/CHANGELOG.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to the LDAP Departments Sync module will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.0] - 2025-11-07
|
||||
|
||||
### Added
|
||||
- Initial stable release of LDAP Departments Sync module
|
||||
- LDAP server and query configuration with dynamic dropdowns
|
||||
- Hierarchical group organization based on LDAP attributes
|
||||
- Dynamic attribute mapping system for flexible field configuration
|
||||
- User reference mapping with DN to Drupal User resolution
|
||||
- Automatic search attribute detection from LDAP server configuration
|
||||
- Comprehensive cron validation to prevent execution with incomplete configurations
|
||||
- Administrative interface with management buttons for LDAP queries
|
||||
- Extensive logging and error handling throughout the synchronization process
|
||||
- Support for both manual and automatic synchronization via cron
|
||||
|
||||
### Features
|
||||
- **LDAP Integration**: Full integration with `ldap_servers` and `ldap_query` modules
|
||||
- **Dynamic Configuration**: AJAX-powered form with real-time updates based on selections
|
||||
- **Hierarchical Groups**: Automatic parent-child relationship mapping from LDAP data
|
||||
- **User Reference Mapping**: Convert LDAP DNs to Drupal User references automatically
|
||||
- **Flexible Mapping**: Support for both simple text and user reference field mappings
|
||||
- **Validation**: Comprehensive configuration validation before cron execution
|
||||
- **Management Tools**: Direct links to edit LDAP queries
|
||||
- **Error Recovery**: Robust error handling with detailed logging for troubleshooting
|
||||
|
||||
### Technical Details
|
||||
- **Drupal Version**: Compatible with Drupal 11
|
||||
- **Dependencies**: group, ldap_servers
|
||||
- **Architecture**: Service-based with dependency injection
|
||||
- **Configuration**: YAML-based with dynamic form interface
|
||||
- **Security**: Defensive coding practices with proper input validation
|
||||
|
||||
### Configuration
|
||||
- LDAP server selection with status verification
|
||||
- Query selection filtered by server with real-time updates
|
||||
- Dynamic attribute mapping with type-specific processing
|
||||
- Hierarchical organization with parent/child attribute configuration
|
||||
- User reference mapping with automatic search attribute detection
|
||||
|
||||
[1.0.0]: https://github.com/your-repo/ldap_departments_sync/releases/tag/v1.0.0
|
||||
184
ldap_departments_sync/README.md
Normal file
184
ldap_departments_sync/README.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# LDAP Departments Sync
|
||||
|
||||
Módulo Drupal para sincronização de departamentos do LDAP com grupos do Drupal.
|
||||
|
||||
## Funcionalidades
|
||||
|
||||
- Sincronização automática de departamentos do LDAP para grupos no Drupal
|
||||
- Mapeamento flexível de atributos LDAP para campos de grupo
|
||||
- Sincronização de membros de departamentos baseada em campos de usuário
|
||||
- Suporte a hierarquia de departamentos
|
||||
- Mapeamento dinâmico de papéis (roles) nos grupos baseado em campos
|
||||
- Campos de referência a departamentos reutilizáveis para content types
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Drupal 10.x ou 11.x
|
||||
- Módulo LDAP (ldap_servers, ldap_query)
|
||||
- Módulo Group
|
||||
- Módulo Entity Reference Views Select (opcional, para widgets avançados)
|
||||
- Módulo Telephone (para campo de telefone)
|
||||
- Módulo Profile (opcional, para usar field_department em profiles)
|
||||
|
||||
## Instalação
|
||||
|
||||
1. Coloque o módulo no diretório `modules/custom/ldap_departments_sync`
|
||||
2. Habilite o módulo: `drush en ldap_departments_sync -y`
|
||||
3. Configure em `/admin/config/ldap/ldap_departments_sync`
|
||||
|
||||
### Instalação da Configuração Padrão
|
||||
|
||||
O módulo inclui configurações opcionais que podem ser instaladas via interface:
|
||||
|
||||
1. Acesse `/admin/config/ldap/ldap_departments_sync`
|
||||
2. Na seção "Tipo de Grupo", clique em "Instalar Configuração Padrão"
|
||||
3. Isso criará:
|
||||
- Tipo de grupo "Departments"
|
||||
- Campos de departamento (código, sigla, tipo, telefone, sala, e-mail, coordenadores)
|
||||
- Roles do grupo (admin, member, etc.)
|
||||
- Displays de visualização e formulário
|
||||
|
||||
## Configuração
|
||||
|
||||
### Mapeamento de Atributos LDAP
|
||||
|
||||
Configure os mapeamentos entre atributos LDAP e campos de grupo em:
|
||||
`/admin/config/ldap/ldap_departments_sync`
|
||||
|
||||
Exemplo de configuração padrão:
|
||||
- `imeccDepartmentCode` → `field_dept_code`
|
||||
- `description` → `label`
|
||||
- `cn` → `field_dept_acronym`
|
||||
- `imeccDepartmentType` → `field_dept_type`
|
||||
- `imeccDepartmentCoord` → `field_dept_coord` (referência a usuário)
|
||||
- `imeccDepartmentAssocCoord` → `field_dept_coord_assoc` (referência a usuário)
|
||||
|
||||
### Sincronização de Membros
|
||||
|
||||
O módulo pode sincronizar automaticamente membros para os grupos baseado em:
|
||||
- Matching entre `field_user_dept_code` (usuário) e `field_dept_code` (grupo)
|
||||
- Atribuição automática de roles baseado em campos de usuário
|
||||
|
||||
### Hierarquia de Departamentos
|
||||
|
||||
Para habilitar hierarquia:
|
||||
1. Marque "Enable Hierarchy"
|
||||
2. Configure:
|
||||
- **Parent Attribute**: atributo LDAP do pai (ex: `departmentNumber`)
|
||||
- **Child Attribute**: atributo LDAP do filho para matching (ex: `imeccDepartmentCode`)
|
||||
|
||||
## Adicionando Campos de Referência a Departamentos
|
||||
|
||||
O módulo fornece um **handler de seleção customizado** que facilita a criação de campos de referência a departamentos em qualquer entidade (nodes, users, profiles, etc.).
|
||||
|
||||
### Como Adicionar um Campo de Departamento
|
||||
|
||||
1. Acesse a página de gerenciamento de campos da entidade desejada:
|
||||
- **Content Types**: `Structure > Content types > [Tipo] > Manage fields`
|
||||
- **User**: `Configuration > People > Account settings > Manage fields`
|
||||
- **Profiles**: `Configuration > People > Profile types > [Tipo] > Manage fields`
|
||||
|
||||
2. Clique em **"Create a new field"**
|
||||
|
||||
3. Em **"Add a new field"**:
|
||||
- Selecione **"Reference"** como categoria
|
||||
- Escolha **"Other..."** (ou "Outro...")
|
||||
- Preencha o **Label** (ex: "Departamento", "Department", "Setor", etc.)
|
||||
- Clique em **"Continue"**
|
||||
|
||||
4. Configure o field storage:
|
||||
- **Type of item to reference**: Selecione **"Group"** (Grupo)
|
||||
- Clique em **"Save field settings"**
|
||||
|
||||
5. Configure as definições do campo:
|
||||
- **Reference method**: Selecione **"Department selection"**
|
||||
- **Group type**: Automaticamente pré-selecionado como **"Departments"**
|
||||
- **Filter by department type**: (Opcional) Marque para filtrar por tipo
|
||||
- **Allowed department types**: (Opcional) Selecione tipos permitidos:
|
||||
- ☐ Acadêmico
|
||||
- ☐ Administrativo
|
||||
- Configure outras opções conforme necessário:
|
||||
- **Required**: Se o campo é obrigatório
|
||||
- **Help text**: Texto de ajuda
|
||||
- **Default value**: Valor padrão
|
||||
- Clique em **"Save settings"**
|
||||
|
||||
### Vantagens desta Abordagem
|
||||
|
||||
- ✅ **Nomes customizáveis**: Escolha qualquer machine name para o campo
|
||||
- ✅ **Múltiplos campos**: Adicione vários campos de departamento no mesmo bundle com propósitos diferentes
|
||||
- ✅ **Filtragem por tipo**: Opção de filtrar apenas departamentos acadêmicos ou administrativos
|
||||
- ✅ **Pré-configurado**: O handler "Department selection" já vem configurado com as opções corretas
|
||||
- ✅ **Flexível**: Use em qualquer tipo de entidade (nodes, users, profiles, custom entities, etc.)
|
||||
|
||||
### Exemplos de Uso
|
||||
|
||||
**Múltiplos campos no mesmo content type:**
|
||||
```
|
||||
Article:
|
||||
- field_primary_department (obrigatório, todos os tipos)
|
||||
- field_secondary_department (opcional, todos os tipos)
|
||||
- field_academic_dept (opcional, apenas acadêmicos)
|
||||
```
|
||||
|
||||
**Diferentes configurações por bundle:**
|
||||
```
|
||||
Student Profile:
|
||||
- field_department (obrigatório, apenas acadêmicos)
|
||||
|
||||
Staff Profile:
|
||||
- field_department (obrigatório, apenas administrativos)
|
||||
```
|
||||
|
||||
## Sincronização Manual
|
||||
|
||||
Execute via Drush:
|
||||
|
||||
```bash
|
||||
drush ldap-departments-sync
|
||||
```
|
||||
|
||||
Ou via interface em `/admin/config/ldap/ldap_departments_sync` clicando em "Sync Now".
|
||||
|
||||
## Sincronização Automática (Cron)
|
||||
|
||||
O módulo sincroniza automaticamente durante a execução do cron do Drupal.
|
||||
|
||||
## Estrutura de Campos do Grupo
|
||||
|
||||
Campos padrão criados para o group type "departments":
|
||||
|
||||
- `field_dept_code` - Código do departamento (texto, obrigatório, único)
|
||||
- `field_dept_acronym` - Sigla/acrônimo
|
||||
- `field_dept_type` - Tipo (acadêmico/administrativo)
|
||||
- `field_dept_phone` - Telefone
|
||||
- `field_dept_room` - Sala
|
||||
- `field_dept_mail` - E-mail
|
||||
- `field_dept_coord` - Coordenador (referência a usuário)
|
||||
- `field_dept_coord_assoc` - Coordenador associado (referência a usuário)
|
||||
- `field_parent_group` - Grupo pai (para hierarquia)
|
||||
|
||||
## Campos de Usuário
|
||||
|
||||
Campos necessários no user entity para sincronização de membros:
|
||||
|
||||
- `field_user_dept_code` - Código do departamento do usuário
|
||||
- `field_user_department` - Referência ao grupo de departamento
|
||||
|
||||
## Desenvolvimento
|
||||
|
||||
### Hooks Disponíveis
|
||||
|
||||
(Documentação futura)
|
||||
|
||||
### API
|
||||
|
||||
(Documentação futura)
|
||||
|
||||
## Licença
|
||||
|
||||
GPL-2.0-or-later
|
||||
|
||||
## Autor
|
||||
|
||||
Desenvolvido para o IME - UNICAMP
|
||||
@@ -0,0 +1,127 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.group.departments.field_dept_acronym
|
||||
- field.field.group.departments.field_dept_code
|
||||
- field.field.group.departments.field_dept_coord
|
||||
- field.field.group.departments.field_dept_coord_assoc
|
||||
- field.field.group.departments.field_dept_mail
|
||||
- field.field.group.departments.field_dept_phone
|
||||
- field.field.group.departments.field_dept_room
|
||||
- field.field.group.departments.field_dept_type
|
||||
- field.field.group.departments.field_parent_group
|
||||
- group.type.departments
|
||||
module:
|
||||
- path
|
||||
id: group.departments.default
|
||||
targetEntityType: group
|
||||
bundle: departments
|
||||
mode: default
|
||||
content:
|
||||
field_dept_acronym:
|
||||
type: string_textfield
|
||||
weight: 123
|
||||
region: content
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_dept_code:
|
||||
type: string_textfield
|
||||
weight: 122
|
||||
region: content
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_dept_coord:
|
||||
type: entity_reference_autocomplete
|
||||
weight: 128
|
||||
region: content
|
||||
settings:
|
||||
match_operator: CONTAINS
|
||||
match_limit: 10
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_dept_coord_assoc:
|
||||
type: entity_reference_autocomplete
|
||||
weight: 129
|
||||
region: content
|
||||
settings:
|
||||
match_operator: CONTAINS
|
||||
match_limit: 10
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_dept_mail:
|
||||
type: email_default
|
||||
weight: 125
|
||||
region: content
|
||||
settings:
|
||||
placeholder: ''
|
||||
size: 60
|
||||
third_party_settings: { }
|
||||
field_dept_phone:
|
||||
type: string_textfield
|
||||
weight: 124
|
||||
region: content
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_dept_room:
|
||||
type: string_textfield
|
||||
weight: 121
|
||||
region: content
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_dept_type:
|
||||
type: options_select
|
||||
weight: 127
|
||||
region: content
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
field_parent_group:
|
||||
type: entity_reference_autocomplete
|
||||
weight: 20
|
||||
region: content
|
||||
settings:
|
||||
match_operator: CONTAINS
|
||||
match_limit: 10
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
label:
|
||||
type: string_textfield
|
||||
weight: -5
|
||||
region: content
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
langcode:
|
||||
type: language_select
|
||||
weight: 2
|
||||
region: content
|
||||
settings:
|
||||
include_locked: true
|
||||
third_party_settings: { }
|
||||
path:
|
||||
type: path
|
||||
weight: 30
|
||||
region: content
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
status:
|
||||
type: boolean_checkbox
|
||||
weight: 120
|
||||
region: content
|
||||
settings:
|
||||
display_label: true
|
||||
third_party_settings: { }
|
||||
hidden:
|
||||
uid: true
|
||||
@@ -0,0 +1,107 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.group.departments.field_dept_acronym
|
||||
- field.field.group.departments.field_dept_code
|
||||
- field.field.group.departments.field_dept_coord
|
||||
- field.field.group.departments.field_dept_coord_assoc
|
||||
- field.field.group.departments.field_dept_mail
|
||||
- field.field.group.departments.field_dept_phone
|
||||
- field.field.group.departments.field_dept_room
|
||||
- field.field.group.departments.field_dept_type
|
||||
- field.field.group.departments.field_parent_group
|
||||
- group.type.departments
|
||||
module:
|
||||
- options
|
||||
id: group.departments.default
|
||||
targetEntityType: group
|
||||
bundle: departments
|
||||
mode: default
|
||||
content:
|
||||
field_dept_acronym:
|
||||
type: string
|
||||
label: above
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
weight: -2
|
||||
region: content
|
||||
field_dept_code:
|
||||
type: string
|
||||
label: above
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
weight: -3
|
||||
region: content
|
||||
field_dept_coord:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 22
|
||||
region: content
|
||||
field_dept_coord_assoc:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 23
|
||||
region: content
|
||||
field_dept_mail:
|
||||
type: basic_string
|
||||
label: above
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
weight: 0
|
||||
region: content
|
||||
field_dept_phone:
|
||||
type: string
|
||||
label: above
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
weight: -1
|
||||
region: content
|
||||
field_dept_room:
|
||||
type: string
|
||||
label: above
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
weight: -4
|
||||
region: content
|
||||
field_dept_type:
|
||||
type: list_default
|
||||
label: above
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
weight: 21
|
||||
region: content
|
||||
field_parent_group:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 20
|
||||
region: content
|
||||
label:
|
||||
type: string
|
||||
label: hidden
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
weight: -5
|
||||
region: content
|
||||
hidden:
|
||||
changed: true
|
||||
created: true
|
||||
entity_print_view_epub: true
|
||||
entity_print_view_pdf: true
|
||||
entity_print_view_word_docx: true
|
||||
langcode: true
|
||||
uid: true
|
||||
@@ -0,0 +1,68 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.user.user.field_user_category
|
||||
- field.field.user.user.field_user_department
|
||||
- field.field.user.user.field_user_dept_code
|
||||
- field.field.user.user.field_user_work_phone
|
||||
|
||||
- field.field.user.user.user_picture
|
||||
- image.style.thumbnail
|
||||
module:
|
||||
- image
|
||||
- telephone
|
||||
- user
|
||||
_core:
|
||||
default_config_hash: mZLyuWM9CQx2ZJVqFGSbzgFnHzudVbHBYmdU256A5Wk
|
||||
id: user.user.default
|
||||
targetEntityType: user
|
||||
bundle: user
|
||||
mode: default
|
||||
content:
|
||||
field_user_category:
|
||||
type: string
|
||||
label: above
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
weight: 3
|
||||
region: content
|
||||
field_user_department:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 10
|
||||
region: content
|
||||
field_user_work_phone:
|
||||
type: telephone_link
|
||||
label: above
|
||||
settings:
|
||||
title: ''
|
||||
third_party_settings: { }
|
||||
weight: 4
|
||||
region: content
|
||||
member_for:
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
weight: 1
|
||||
region: content
|
||||
user_picture:
|
||||
type: image
|
||||
label: hidden
|
||||
settings:
|
||||
image_link: content
|
||||
image_style: thumbnail
|
||||
image_loading:
|
||||
attribute: lazy
|
||||
third_party_settings: { }
|
||||
weight: 0
|
||||
region: content
|
||||
hidden:
|
||||
entity_print_view_epub: true
|
||||
entity_print_view_pdf: true
|
||||
entity_print_view_word_docx: true
|
||||
field_user_dept_code: true
|
||||
langcode: true
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_dept_acronym
|
||||
- group.type.departments
|
||||
id: group.departments.field_dept_acronym
|
||||
field_name: field_dept_acronym
|
||||
entity_type: group
|
||||
bundle: departments
|
||||
label: Sigla
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: string
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_dept_code
|
||||
- group.type.departments
|
||||
id: group.departments.field_dept_code
|
||||
field_name: field_dept_code
|
||||
entity_type: group
|
||||
bundle: departments
|
||||
label: Código
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: string
|
||||
@@ -0,0 +1,28 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_dept_coord
|
||||
- group.type.departments
|
||||
id: group.departments.field_dept_coord
|
||||
field_name: field_dept_coord
|
||||
entity_type: group
|
||||
bundle: departments
|
||||
label: Coordenador
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: 'default:user'
|
||||
handler_settings:
|
||||
target_bundles: null
|
||||
sort:
|
||||
field: _none
|
||||
direction: ASC
|
||||
auto_create: false
|
||||
filter:
|
||||
type: _none
|
||||
include_anonymous: false
|
||||
field_type: entity_reference
|
||||
@@ -0,0 +1,28 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_dept_coord_assoc
|
||||
- group.type.departments
|
||||
id: group.departments.field_dept_coord_assoc
|
||||
field_name: field_dept_coord_assoc
|
||||
entity_type: group
|
||||
bundle: departments
|
||||
label: 'Coordenador Associado'
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: 'default:user'
|
||||
handler_settings:
|
||||
target_bundles: null
|
||||
sort:
|
||||
field: _none
|
||||
direction: ASC
|
||||
auto_create: false
|
||||
filter:
|
||||
type: _none
|
||||
include_anonymous: false
|
||||
field_type: entity_reference
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_dept_mail
|
||||
- group.type.departments
|
||||
id: group.departments.field_dept_mail
|
||||
field_name: field_dept_mail
|
||||
entity_type: group
|
||||
bundle: departments
|
||||
label: Email
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: email
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_dept_phone
|
||||
- group.type.departments
|
||||
id: group.departments.field_dept_phone
|
||||
field_name: field_dept_phone
|
||||
entity_type: group
|
||||
bundle: departments
|
||||
label: Telefone
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: string
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_dept_room
|
||||
- group.type.departments
|
||||
id: group.departments.field_dept_room
|
||||
field_name: field_dept_room
|
||||
entity_type: group
|
||||
bundle: departments
|
||||
label: Sala
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: string
|
||||
@@ -0,0 +1,20 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_dept_type
|
||||
- group.type.departments
|
||||
module:
|
||||
- options
|
||||
id: group.departments.field_dept_type
|
||||
field_name: field_dept_type
|
||||
entity_type: group
|
||||
bundle: departments
|
||||
label: 'Tipo'
|
||||
description: 'Tipo do departamento (Administrativo ou Acadêmico)'
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: list_string
|
||||
@@ -0,0 +1,27 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_parent_group
|
||||
- group.type.departments
|
||||
id: group.departments.field_parent_group
|
||||
field_name: field_parent_group
|
||||
entity_type: group
|
||||
bundle: departments
|
||||
label: 'Órgão superior'
|
||||
description: 'Grupo pai na hierarquia de departamentos'
|
||||
required: false
|
||||
translatable: true
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: 'default:group'
|
||||
handler_settings:
|
||||
target_bundles:
|
||||
departments: departments
|
||||
sort:
|
||||
field: _none
|
||||
direction: ASC
|
||||
auto_create: false
|
||||
auto_create_bundle: ''
|
||||
field_type: entity_reference
|
||||
@@ -0,0 +1,19 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.user.field_user_category
|
||||
module:
|
||||
- user
|
||||
id: user.user.field_user_category
|
||||
field_name: field_user_category
|
||||
entity_type: user
|
||||
bundle: user
|
||||
label: Category
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: string
|
||||
@@ -0,0 +1,24 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.user.field_user_department
|
||||
module:
|
||||
- user
|
||||
id: user.user.field_user_department
|
||||
field_name: field_user_department
|
||||
entity_type: user
|
||||
bundle: user
|
||||
label: Departamento
|
||||
description: 'Departamento do usuário sincronizado do LDAP'
|
||||
required: false
|
||||
translatable: true
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: views
|
||||
handler_settings:
|
||||
view:
|
||||
view_name: departments
|
||||
display_name: entity_reference_1
|
||||
field_type: entity_reference
|
||||
@@ -0,0 +1,19 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.user.field_user_dept_code
|
||||
module:
|
||||
- user
|
||||
id: user.user.field_user_dept_code
|
||||
field_name: field_user_dept_code
|
||||
entity_type: user
|
||||
bundle: user
|
||||
label: 'Department Code'
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: string
|
||||
@@ -0,0 +1,20 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.user.field_user_work_phone
|
||||
module:
|
||||
- telephone
|
||||
- user
|
||||
id: user.user.field_user_work_phone
|
||||
field_name: field_user_work_phone
|
||||
entity_type: user
|
||||
bundle: user
|
||||
label: 'Work Phone'
|
||||
description: 'Work phone number, populated from LDAP.'
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: telephone
|
||||
@@ -0,0 +1,20 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
id: group.field_dept_acronym
|
||||
field_name: field_dept_acronym
|
||||
entity_type: group
|
||||
type: string
|
||||
settings:
|
||||
max_length: 255
|
||||
case_sensitive: false
|
||||
is_ascii: false
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,20 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
id: group.field_dept_code
|
||||
field_name: field_dept_code
|
||||
entity_type: group
|
||||
type: string
|
||||
settings:
|
||||
max_length: 255
|
||||
case_sensitive: false
|
||||
is_ascii: false
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,19 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
- user
|
||||
id: group.field_dept_coord
|
||||
field_name: field_dept_coord
|
||||
entity_type: group
|
||||
type: entity_reference
|
||||
settings:
|
||||
target_type: user
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,19 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
- user
|
||||
id: group.field_dept_coord_assoc
|
||||
field_name: field_dept_coord_assoc
|
||||
entity_type: group
|
||||
type: entity_reference
|
||||
settings:
|
||||
target_type: user
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,17 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
id: group.field_dept_mail
|
||||
field_name: field_dept_mail
|
||||
entity_type: group
|
||||
type: email
|
||||
settings: { }
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,20 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
id: group.field_dept_phone
|
||||
field_name: field_dept_phone
|
||||
entity_type: group
|
||||
type: string
|
||||
settings:
|
||||
max_length: 255
|
||||
case_sensitive: false
|
||||
is_ascii: false
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,20 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
id: group.field_dept_room
|
||||
field_name: field_dept_room
|
||||
entity_type: group
|
||||
type: string
|
||||
settings:
|
||||
max_length: 255
|
||||
case_sensitive: false
|
||||
is_ascii: false
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,26 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
- options
|
||||
id: group.field_dept_type
|
||||
field_name: field_dept_type
|
||||
entity_type: group
|
||||
type: list_string
|
||||
settings:
|
||||
allowed_values:
|
||||
-
|
||||
value: academico
|
||||
label: Acadêmico
|
||||
-
|
||||
value: administrativo
|
||||
label: Administrativo
|
||||
allowed_values_function: ''
|
||||
module: options
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
id: group.field_parent_group
|
||||
field_name: field_parent_group
|
||||
entity_type: group
|
||||
type: entity_reference
|
||||
settings:
|
||||
target_type: group
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,20 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: user.field_user_category
|
||||
field_name: field_user_category
|
||||
entity_type: user
|
||||
type: string
|
||||
settings:
|
||||
max_length: 255
|
||||
case_sensitive: false
|
||||
is_ascii: false
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,19 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
- user
|
||||
id: user.field_user_department
|
||||
field_name: field_user_department
|
||||
entity_type: user
|
||||
type: entity_reference
|
||||
settings:
|
||||
target_type: group
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,20 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: user.field_user_dept_code
|
||||
field_name: field_user_dept_code
|
||||
entity_type: user
|
||||
type: string
|
||||
settings:
|
||||
max_length: 255
|
||||
case_sensitive: false
|
||||
is_ascii: false
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- telephone
|
||||
- user
|
||||
id: user.field_user_work_phone
|
||||
field_name: field_user_work_phone
|
||||
entity_type: user
|
||||
type: telephone
|
||||
settings: { }
|
||||
module: telephone
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,45 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.departments
|
||||
id: departments-admin
|
||||
label: Admin
|
||||
weight: 100
|
||||
admin: true
|
||||
scope: individual
|
||||
global_role: null
|
||||
group_type: departments
|
||||
permissions:
|
||||
- administer members
|
||||
- delete group
|
||||
- edit group
|
||||
- leave group
|
||||
- view group
|
||||
- view unpublished group
|
||||
- access group_media overview
|
||||
- access group_node overview
|
||||
- create group_node:article entity
|
||||
- create group_node:page entity
|
||||
- create group_node:webform entity
|
||||
- delete any group_node:article entity
|
||||
- delete any group_node:page entity
|
||||
- delete any group_node:webform entity
|
||||
- delete own group_node:article entity
|
||||
- delete own group_node:page entity
|
||||
- delete own group_node:webform entity
|
||||
- update any group_node:article entity
|
||||
- update any group_node:page entity
|
||||
- update any group_node:webform entity
|
||||
- update own group_node:article entity
|
||||
- update own group_node:page entity
|
||||
- update own group_node:webform entity
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
- view group_node:webform entity
|
||||
- view own unpublished group_node:article entity
|
||||
- view own unpublished group_node:page entity
|
||||
- view own unpublished group_node:webform entity
|
||||
- view unpublished group_node:article entity
|
||||
- view unpublished group_node:page entity
|
||||
- view unpublished group_node:webform entity
|
||||
@@ -0,0 +1,46 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.departments
|
||||
- user.role.administrator
|
||||
id: departments-admin_in
|
||||
label: Administrador
|
||||
weight: 102
|
||||
admin: true
|
||||
scope: insider
|
||||
global_role: administrator
|
||||
group_type: departments
|
||||
permissions:
|
||||
- administer members
|
||||
- delete group
|
||||
- edit group
|
||||
- leave group
|
||||
- view group
|
||||
- view unpublished group
|
||||
- access group_media overview
|
||||
- access group_node overview
|
||||
- create group_node:article entity
|
||||
- create group_node:page entity
|
||||
- create group_node:webform entity
|
||||
- delete any group_node:article entity
|
||||
- delete any group_node:page entity
|
||||
- delete any group_node:webform entity
|
||||
- delete own group_node:article entity
|
||||
- delete own group_node:page entity
|
||||
- delete own group_node:webform entity
|
||||
- update any group_node:article entity
|
||||
- update any group_node:page entity
|
||||
- update any group_node:webform entity
|
||||
- update own group_node:article entity
|
||||
- update own group_node:page entity
|
||||
- update own group_node:webform entity
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
- view group_node:webform entity
|
||||
- view own unpublished group_node:article entity
|
||||
- view own unpublished group_node:page entity
|
||||
- view own unpublished group_node:webform entity
|
||||
- view unpublished group_node:article entity
|
||||
- view unpublished group_node:page entity
|
||||
- view unpublished group_node:webform entity
|
||||
@@ -0,0 +1,46 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.departments
|
||||
- user.role.administrator
|
||||
id: departments-admin_out
|
||||
label: Administrador
|
||||
weight: 101
|
||||
admin: true
|
||||
scope: outsider
|
||||
global_role: administrator
|
||||
group_type: departments
|
||||
permissions:
|
||||
- administer members
|
||||
- delete group
|
||||
- edit group
|
||||
- join group
|
||||
- view group
|
||||
- view unpublished group
|
||||
- access group_media overview
|
||||
- access group_node overview
|
||||
- create group_node:article entity
|
||||
- create group_node:page entity
|
||||
- create group_node:webform entity
|
||||
- delete any group_node:article entity
|
||||
- delete any group_node:page entity
|
||||
- delete any group_node:webform entity
|
||||
- delete own group_node:article entity
|
||||
- delete own group_node:page entity
|
||||
- delete own group_node:webform entity
|
||||
- update any group_node:article entity
|
||||
- update any group_node:page entity
|
||||
- update any group_node:webform entity
|
||||
- update own group_node:article entity
|
||||
- update own group_node:page entity
|
||||
- update own group_node:webform entity
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
- view group_node:webform entity
|
||||
- view own unpublished group_node:article entity
|
||||
- view own unpublished group_node:page entity
|
||||
- view own unpublished group_node:webform entity
|
||||
- view unpublished group_node:article entity
|
||||
- view unpublished group_node:page entity
|
||||
- view unpublished group_node:webform entity
|
||||
@@ -0,0 +1,17 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.departments
|
||||
- user.role.anonymous
|
||||
id: departments-anonymous
|
||||
label: Anônimo
|
||||
weight: -102
|
||||
admin: false
|
||||
scope: outsider
|
||||
global_role: anonymous
|
||||
group_type: departments
|
||||
permissions:
|
||||
- view group
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
@@ -0,0 +1,36 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.departments
|
||||
- user.role.authenticated
|
||||
id: departments-member
|
||||
label: Member
|
||||
weight: -100
|
||||
admin: false
|
||||
scope: insider
|
||||
global_role: authenticated
|
||||
group_type: departments
|
||||
permissions:
|
||||
- view group
|
||||
- access group_media overview
|
||||
- access group_node overview
|
||||
- create group_node:article entity
|
||||
- create group_node:page entity
|
||||
- create group_node:webform entity
|
||||
- delete own group_node:article entity
|
||||
- delete own group_node:page entity
|
||||
- delete own group_node:webform entity
|
||||
- update any group_node:webform entity
|
||||
- update own group_node:article entity
|
||||
- update own group_node:page entity
|
||||
- update own group_node:webform entity
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
- view group_node:webform entity
|
||||
- view own unpublished group_node:article entity
|
||||
- view own unpublished group_node:page entity
|
||||
- view own unpublished group_node:webform entity
|
||||
- view unpublished group_node:article entity
|
||||
- view unpublished group_node:page entity
|
||||
- view unpublished group_node:webform entity
|
||||
@@ -0,0 +1,17 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.departments
|
||||
- user.role.authenticated
|
||||
id: departments-outsider
|
||||
label: Outsider
|
||||
weight: -101
|
||||
admin: false
|
||||
scope: outsider
|
||||
global_role: authenticated
|
||||
group_type: departments
|
||||
permissions:
|
||||
- view group
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
@@ -0,0 +1,10 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies: { }
|
||||
id: departments
|
||||
label: Departamento
|
||||
description: ''
|
||||
new_revision: true
|
||||
creator_membership: true
|
||||
creator_wizard: true
|
||||
creator_roles: { }
|
||||
@@ -0,0 +1,2 @@
|
||||
label: 'Telefone Profissional'
|
||||
description: 'Número de telefone profissional, populado via LDAP.'
|
||||
73
ldap_departments_sync/css/role-mapping.css
Normal file
73
ldap_departments_sync/css/role-mapping.css
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Role mapping table styles
|
||||
*/
|
||||
|
||||
/* Limita a largura da tabela e permite scroll horizontal se necessário */
|
||||
.role-mappings-table {
|
||||
max-width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
/* Define larguras fixas para cada coluna */
|
||||
.role-mappings-table th:nth-child(1),
|
||||
.role-mappings-table td:nth-child(1) {
|
||||
width: 20%;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.role-mappings-table th:nth-child(2),
|
||||
.role-mappings-table td:nth-child(2) {
|
||||
width: 15%;
|
||||
min-width: 130px;
|
||||
}
|
||||
|
||||
.role-mappings-table th:nth-child(3),
|
||||
.role-mappings-table td:nth-child(3) {
|
||||
width: 25%;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.role-mappings-table th:nth-child(4),
|
||||
.role-mappings-table td:nth-child(4) {
|
||||
width: 30%;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.role-mappings-table th:nth-child(5),
|
||||
.role-mappings-table td:nth-child(5) {
|
||||
width: 10%;
|
||||
min-width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Estilo dos selects para limitar largura e truncar texto */
|
||||
.role-mapping-field-select {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Estilo para options dentro dos selects - mostra texto completo no dropdown */
|
||||
.role-mapping-field-select option {
|
||||
white-space: normal;
|
||||
overflow: visible;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
/* Estilo do textarea */
|
||||
.role-mapping-values-textarea {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
/* Responsividade: em telas menores, permite scroll horizontal */
|
||||
@media (max-width: 1200px) {
|
||||
.role-mappings-table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
13
ldap_departments_sync/ldap_departments_sync.info.yml
Normal file
13
ldap_departments_sync/ldap_departments_sync.info.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
name: LDAP Departments Sync
|
||||
type: module
|
||||
description: 'Sincroniza departamentos do servidor LDAP com grupos via cron'
|
||||
version: '1.1.0'
|
||||
core_version_requirement: ^11
|
||||
package: Custom
|
||||
dependencies:
|
||||
- ldap_groups_sync:ldap_groups_sync
|
||||
- drupal:options
|
||||
- drupal:telephone
|
||||
- group:group
|
||||
- ldap:ldap_servers
|
||||
- site_tools
|
||||
106
ldap_departments_sync/ldap_departments_sync.install
Normal file
106
ldap_departments_sync/ldap_departments_sync.install
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Arquivo de instalação para ldap_departments_sync.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function ldap_departments_sync_install() {
|
||||
\Drupal::messenger()->addWarning(t('Please ensure your group type has the required fields: field_dept_code, field_dept_acronym, field_dept_type, field_dept_phone, field_dept_room, field_dept_mail, and field_parent_group (for hierarchy).'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames field_user_phone_number to field_user_work_phone.
|
||||
*/
|
||||
function ldap_departments_sync_update_10001() {
|
||||
// 1. Create new field storage.
|
||||
if (!FieldStorageConfig::loadByName('user', 'field_user_work_phone')) {
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => 'field_user_work_phone',
|
||||
'entity_type' => 'user',
|
||||
'type' => 'telephone',
|
||||
'cardinality' => 1,
|
||||
'translatable' => TRUE,
|
||||
])->save();
|
||||
}
|
||||
|
||||
// 2. Create new field instance.
|
||||
if (!FieldConfig::loadByName('user', 'user', 'field_user_work_phone')) {
|
||||
FieldConfig::create([
|
||||
'field_name' => 'field_user_work_phone',
|
||||
'entity_type' => 'user',
|
||||
'bundle' => 'user',
|
||||
'label' => 'Work Phone',
|
||||
'description' => 'Work phone number, populated from LDAP.',
|
||||
'required' => FALSE,
|
||||
'translatable' => FALSE,
|
||||
])->save();
|
||||
}
|
||||
|
||||
// 3. Copy data directly via SQL — efficient and side-effect-free.
|
||||
$database = \Drupal::database();
|
||||
$schema = $database->schema();
|
||||
foreach (['user__', 'user_revision__'] as $prefix) {
|
||||
$old_table = $prefix . 'field_user_phone_number';
|
||||
$new_table = $prefix . 'field_user_work_phone';
|
||||
if ($schema->tableExists($old_table) && $schema->tableExists($new_table)) {
|
||||
$database->query("
|
||||
INSERT INTO {{$new_table}}
|
||||
(bundle, deleted, entity_id, revision_id, langcode, delta, field_user_work_phone_value)
|
||||
SELECT bundle, deleted, entity_id, revision_id, langcode, delta, field_user_phone_number_value
|
||||
FROM {{$old_table}}
|
||||
WHERE deleted = 0
|
||||
");
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Update form display.
|
||||
$form_display = EntityFormDisplay::load('user.user.default');
|
||||
if ($form_display) {
|
||||
$component = $form_display->getComponent('field_user_phone_number');
|
||||
if ($component) {
|
||||
$form_display->removeComponent('field_user_phone_number');
|
||||
$form_display->setComponent('field_user_work_phone', $component);
|
||||
$form_display->save();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Update view display.
|
||||
$view_display = EntityViewDisplay::load('user.user.default');
|
||||
if ($view_display) {
|
||||
$component = $view_display->getComponent('field_user_phone_number');
|
||||
if ($component) {
|
||||
$view_display->removeComponent('field_user_phone_number');
|
||||
$view_display->setComponent('field_user_work_phone', $component);
|
||||
$view_display->save();
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Delete old field instance then storage.
|
||||
if ($old_config = FieldConfig::loadByName('user', 'user', 'field_user_phone_number')) {
|
||||
$old_config->delete();
|
||||
}
|
||||
if ($old_storage = FieldStorageConfig::loadByName('user', 'field_user_phone_number')) {
|
||||
$old_storage->delete();
|
||||
}
|
||||
|
||||
return t('Renamed field_user_phone_number to field_user_work_phone.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function ldap_departments_sync_uninstall() {
|
||||
// Remove configurações
|
||||
\Drupal::configFactory()->getEditable('ldap_departments_sync.settings')->delete();
|
||||
|
||||
\Drupal::messenger()->addStatus(t('Módulo LDAP Departments Sync desinstalado.'));
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
role_mapping_styles:
|
||||
version: 1.x
|
||||
css:
|
||||
theme:
|
||||
css/role-mapping.css: {}
|
||||
@@ -0,0 +1,6 @@
|
||||
ldap_departments_sync.config:
|
||||
title: 'LDAP Departments Sync'
|
||||
description: 'Configurar sincronização de departamentos do LDAP'
|
||||
route_name: ldap_departments_sync.config
|
||||
parent: site_tools.admin_config
|
||||
weight: 5
|
||||
11
ldap_departments_sync/ldap_departments_sync.links.task.yml
Normal file
11
ldap_departments_sync/ldap_departments_sync.links.task.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
ldap_departments_sync.tab.config:
|
||||
title: 'Configuration'
|
||||
route_name: ldap_departments_sync.config
|
||||
base_route: ldap_departments_sync.config
|
||||
weight: 0
|
||||
|
||||
ldap_departments_sync.tab.access_rules:
|
||||
title: 'Access Rules'
|
||||
route_name: ldap_departments_sync.access_rules
|
||||
base_route: ldap_departments_sync.config
|
||||
weight: 10
|
||||
291
ldap_departments_sync/ldap_departments_sync.module
Normal file
291
ldap_departments_sync/ldap_departments_sync.module
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Module to synchronize departments from LDAP to groups.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\field\FieldConfigInterface;
|
||||
use Drupal\ldap_departments_sync\LdapDepartmentsSync;
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function ldap_departments_sync_help($route_name, RouteMatchInterface $route_match) {
|
||||
switch ($route_name) {
|
||||
case 'help.page.ldap_departments_sync':
|
||||
return '<p>' . t('This module synchronizes departments from an LDAP server to groups through cron.') . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_cron().
|
||||
*/
|
||||
function ldap_departments_sync_cron() {
|
||||
// Check if module is properly configured
|
||||
$config = \Drupal::config('ldap_departments_sync.settings');
|
||||
$ldap_server_id = $config->get('ldap_server_id');
|
||||
$ldap_query_id = $config->get('ldap_query_id');
|
||||
|
||||
// Validate LDAP server
|
||||
try {
|
||||
$entity_type_manager = \Drupal::entityTypeManager();
|
||||
$server_storage = $entity_type_manager->getStorage('ldap_server');
|
||||
$server = $server_storage->load($ldap_server_id);
|
||||
|
||||
if (!$server || !$server->get('status')) {
|
||||
\Drupal::logger('ldap_departments_sync')->warning('Synchronization cancelled: LDAP server "@server_id" not found or inactive. Configure at /admin/config/local-modules/ldap-departments-sync', [
|
||||
'@server_id' => $ldap_server_id,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
\Drupal::logger('ldap_departments_sync')->warning('Synchronization cancelled: error checking LDAP server: @message', [
|
||||
'@message' => $e->getMessage(),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate LDAP query
|
||||
try {
|
||||
if ($entity_type_manager->hasDefinition('ldap_query_entity')) {
|
||||
$query_storage = $entity_type_manager->getStorage('ldap_query_entity');
|
||||
$query = $query_storage->load($ldap_query_id);
|
||||
|
||||
if (!$query || !$query->get('status')) {
|
||||
\Drupal::logger('ldap_departments_sync')->warning('Synchronization cancelled: LDAP query "@query_id" not found or inactive. Configure at /admin/config/local-modules/ldap-departments-sync', [
|
||||
'@query_id' => $ldap_query_id,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
\Drupal::logger('ldap_departments_sync')->warning('Synchronization cancelled: ldap_query module not available.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
\Drupal::logger('ldap_departments_sync')->warning('Synchronization cancelled: error checking LDAP query: @message', [
|
||||
'@message' => $e->getMessage(),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate group type
|
||||
try {
|
||||
$group_type_id = $config->get('group_type_id');
|
||||
$group_type_storage = $entity_type_manager->getStorage('group_type');
|
||||
$group_type = $group_type_storage->load($group_type_id);
|
||||
|
||||
if (!$group_type) {
|
||||
\Drupal::logger('ldap_departments_sync')->warning('Synchronization cancelled: group type "@type_id" not found. Configure at /admin/config/local-modules/ldap-departments-sync', [
|
||||
'@type_id' => $group_type_id,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
\Drupal::logger('ldap_departments_sync')->warning('Synchronization cancelled: error checking group type: @message', [
|
||||
'@message' => $e->getMessage(),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get LDAP synchronization service
|
||||
$ldap_sync = \Drupal::service('ldap_departments_sync.sync');
|
||||
|
||||
// Execute departments synchronization
|
||||
try {
|
||||
$ldap_sync->syncDepartments();
|
||||
\Drupal::logger('ldap_departments_sync')->info('Departments synchronization executed successfully.');
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
\Drupal::logger('ldap_departments_sync')->error('Error in departments synchronization: @message', [
|
||||
'@message' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_access().
|
||||
*
|
||||
* Evaluates access rules configured in the module settings for view, update
|
||||
* and delete operations on existing entities.
|
||||
*/
|
||||
function ldap_departments_sync_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
// Skip group-related entities to avoid conflicts with the group module.
|
||||
$skip_types = ['group', 'group_content', 'group_relationship', 'group_role', 'group_type'];
|
||||
if (in_array($entity->getEntityTypeId(), $skip_types, TRUE)) {
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
return \Drupal::service('ldap_departments_sync.access_rules')
|
||||
->checkAccess($entity, $operation, $account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_create_access().
|
||||
*
|
||||
* Evaluates access rules configured in the module settings for create
|
||||
* operations on new entities.
|
||||
*/
|
||||
function ldap_departments_sync_entity_create_access(AccountInterface $account, array $context, $entity_bundle) {
|
||||
$entity_type_id = $context['entity_type_id'] ?? '';
|
||||
|
||||
// Skip group-related entities.
|
||||
$skip_types = ['group', 'group_content', 'group_relationship', 'group_role', 'group_type'];
|
||||
if (in_array($entity_type_id, $skip_types, TRUE)) {
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
return \Drupal::service('ldap_departments_sync.access_rules')
|
||||
->checkCreateAccess($account, $entity_type_id, $entity_bundle ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_field_access().
|
||||
*
|
||||
* Nega acesso de edição aos campos gerenciados pelo LDAP sync em formulários
|
||||
* e APIs (REST, JSON:API). Saves programáticos não são afetados.
|
||||
*
|
||||
* Campos protegidos no usuário:
|
||||
* - field_user_category: categoria do usuário, populado pelo ldap_user.
|
||||
* - field_user_dept_code: código do departamento, populado pelo ldap_user.
|
||||
* - field_user_department: referência ao grupo, populado pelo nosso sync.
|
||||
* Proteger este campo evita o erro de validação "Esta entidade não pode
|
||||
* ser referenciada" que ocorre quando o widget tenta validar o grupo
|
||||
* referenciado contra o acesso do usuário atual.
|
||||
* - field_user_work_phone: telefone de trabalho, populado pelo ldap_user.
|
||||
*/
|
||||
function ldap_departments_sync_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, ?FieldItemListInterface $items = NULL) {
|
||||
$protected_user_fields = [
|
||||
'field_user_category',
|
||||
'field_user_dept_code',
|
||||
'field_user_department',
|
||||
'field_user_work_phone',
|
||||
];
|
||||
|
||||
if (
|
||||
$field_definition->getTargetEntityTypeId() === 'user' &&
|
||||
in_array($field_definition->getName(), $protected_user_fields, TRUE) &&
|
||||
$operation === 'edit'
|
||||
) {
|
||||
// Sempre nega edição via UI/API, inclusive para o uid 1.
|
||||
// Saves programáticos (ldap_user, drush) não passam por este hook.
|
||||
return AccessResult::forbidden('This field is managed exclusively by LDAP synchronization.');
|
||||
}
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_user_presave().
|
||||
*
|
||||
* Protege os campos gerenciados pelo LDAP sync de alterações programáticas
|
||||
* não autorizadas em usuários existentes. Permite:
|
||||
* - Saves durante sync LDAP autorizado (LdapDepartmentsSync::$syncing TRUE)
|
||||
* - Criação de novos usuários (provisionamento inicial via ldap_user)
|
||||
* - Salvas por usuários com a permissão 'edit ldap managed user fields'
|
||||
*/
|
||||
function ldap_departments_sync_user_presave(\Drupal\user\UserInterface $user) {
|
||||
// Permite durante qualquer sync LDAP autorizado.
|
||||
if (LdapDepartmentsSync::isSyncing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Permite na criação inicial do usuário (primeiro login LDAP).
|
||||
if ($user->isNew()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Permite se o usuário atual tem a permissão de bypass.
|
||||
if (\Drupal::currentUser()->hasPermission('edit ldap managed user fields')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$original = $user->original;
|
||||
if ($original === NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Campos gerenciados pelo LDAP que não podem ser alterados externamente.
|
||||
$protected_fields = [
|
||||
'field_user_category',
|
||||
'field_user_dept_code',
|
||||
'field_user_department',
|
||||
'field_user_work_phone',
|
||||
];
|
||||
|
||||
foreach ($protected_fields as $field_name) {
|
||||
if (!$user->hasField($field_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$original_value = $original->get($field_name)->getValue();
|
||||
$new_value = $user->get($field_name)->getValue();
|
||||
|
||||
if ($original_value !== $new_value) {
|
||||
$user->set($field_name, $original_value);
|
||||
\Drupal::logger('ldap_departments_sync')->warning(
|
||||
'Tentativa não autorizada de alterar @field do usuário @username foi bloqueada. Use a sincronização LDAP para atualizar este campo.',
|
||||
[
|
||||
'@field' => $field_name,
|
||||
'@username' => $user->getAccountName(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_predelete() for user entities.
|
||||
*
|
||||
* Cleans up user references in department groups when a user is deleted.
|
||||
*/
|
||||
function ldap_departments_sync_user_predelete(\Drupal\user\UserInterface $user) {
|
||||
$config = \Drupal::config('ldap_departments_sync.settings');
|
||||
$group_type_id = $config->get('group_type_id') ?: 'departments';
|
||||
|
||||
// Fields that may contain user references
|
||||
$user_reference_fields = [
|
||||
'field_dept_coord',
|
||||
'field_dept_coord_assoc',
|
||||
];
|
||||
|
||||
try {
|
||||
$group_storage = \Drupal::entityTypeManager()->getStorage('group');
|
||||
$user_id = $user->id();
|
||||
|
||||
// Find groups that reference this user
|
||||
foreach ($user_reference_fields as $field_name) {
|
||||
$groups = $group_storage->loadByProperties([
|
||||
'type' => $group_type_id,
|
||||
$field_name => $user_id,
|
||||
]);
|
||||
|
||||
foreach ($groups as $group) {
|
||||
if ($group->hasField($field_name)) {
|
||||
$group->set($field_name, NULL);
|
||||
$group->save();
|
||||
\Drupal::logger('ldap_departments_sync')->info('Removed user @username reference from @field in group @group', [
|
||||
'@username' => $user->getAccountName(),
|
||||
'@field' => $field_name,
|
||||
'@group' => $group->label(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
\Drupal::logger('ldap_departments_sync')->error('Error cleaning up user references: @message', [
|
||||
'@message' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
administer ldap departments sync:
|
||||
title: 'Administrar LDAP Departments Sync'
|
||||
description: 'Configurar sincronização de departamentos do LDAP'
|
||||
restrict access: true
|
||||
|
||||
edit ldap managed user fields:
|
||||
title: 'Editar campos gerenciados pelo LDAP no usuário'
|
||||
description: 'Permite editar manualmente campos como field_user_dept_code que são normalmente gerenciados pelo LDAP. Use apenas em emergências.'
|
||||
restrict access: true
|
||||
25
ldap_departments_sync/ldap_departments_sync.routing.yml
Normal file
25
ldap_departments_sync/ldap_departments_sync.routing.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
ldap_departments_sync.config:
|
||||
path: '/admin/config/local-modules/ldap-departments-sync'
|
||||
defaults:
|
||||
_form: '\Drupal\ldap_departments_sync\Form\LdapDepartmentsSyncConfigForm'
|
||||
_title: 'LDAP Departments Sync'
|
||||
requirements:
|
||||
_permission: 'administer ldap departments sync'
|
||||
|
||||
ldap_departments_sync.access_rules:
|
||||
path: '/admin/config/local-modules/ldap-departments-sync/access-rules'
|
||||
defaults:
|
||||
_form: '\Drupal\ldap_departments_sync\Form\AccessRulesForm'
|
||||
_title: 'Access Rules'
|
||||
requirements:
|
||||
_permission: 'administer ldap departments sync'
|
||||
|
||||
ldap_departments_sync.access_rule_form:
|
||||
path: '/admin/config/local-modules/ldap-departments-sync/access-rule/{rule_index}'
|
||||
defaults:
|
||||
_form: '\Drupal\ldap_departments_sync\Form\AccessRuleForm'
|
||||
_title: 'Access Rule'
|
||||
rule_index: 'new'
|
||||
requirements:
|
||||
_permission: 'administer ldap departments sync'
|
||||
rule_index: 'new|\d+'
|
||||
8
ldap_departments_sync/ldap_departments_sync.services.yml
Normal file
8
ldap_departments_sync/ldap_departments_sync.services.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
services:
|
||||
ldap_departments_sync.sync:
|
||||
class: Drupal\ldap_departments_sync\LdapDepartmentsSync
|
||||
arguments: ['@entity_type.manager', '@config.factory', '@logger.factory', '@ldap.bridge']
|
||||
|
||||
ldap_departments_sync.access_rules:
|
||||
class: Drupal\ldap_groups_sync\GroupAccessRulesService
|
||||
arguments: ['@config.factory', '@entity_type.manager', 'ldap_departments_sync.settings']
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ldap_departments_sync\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
|
||||
/**
|
||||
* Controller para títulos traduzíveis.
|
||||
*/
|
||||
class LocalModulesController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Retorna título traduzível para a página Local Modules.
|
||||
*
|
||||
* @return string
|
||||
* Título traduzido.
|
||||
*/
|
||||
public function getTitle() {
|
||||
return $this->t('Local Modules');
|
||||
}
|
||||
|
||||
}
|
||||
40
ldap_departments_sync/src/Form/AccessRuleForm.php
Normal file
40
ldap_departments_sync/src/Form/AccessRuleForm.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ldap_departments_sync\Form;
|
||||
|
||||
use Drupal\ldap_groups_sync\Form\AccessRuleFormBase;
|
||||
|
||||
/**
|
||||
* Modal form for creating or editing a single access rule (Departments Sync).
|
||||
*/
|
||||
class AccessRuleForm extends AccessRuleFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigName(): string {
|
||||
return 'ldap_departments_sync.settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId(): string {
|
||||
return 'ldap_departments_sync_access_rule_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAccessRulesRoute(): string {
|
||||
return 'ldap_departments_sync.access_rules';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultGroupTypeId(): string {
|
||||
return 'departments';
|
||||
}
|
||||
|
||||
}
|
||||
33
ldap_departments_sync/src/Form/AccessRulesForm.php
Normal file
33
ldap_departments_sync/src/Form/AccessRulesForm.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ldap_departments_sync\Form;
|
||||
|
||||
use Drupal\ldap_groups_sync\Form\AccessRulesFormBase;
|
||||
|
||||
/**
|
||||
* Lists and manages access rules for the LDAP Departments Sync module.
|
||||
*/
|
||||
class AccessRulesForm extends AccessRulesFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigName(): string {
|
||||
return 'ldap_departments_sync.settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId(): string {
|
||||
return 'ldap_departments_sync_access_rules_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAccessRuleFormRoute(): string {
|
||||
return 'ldap_departments_sync.access_rule_form';
|
||||
}
|
||||
|
||||
}
|
||||
1517
ldap_departments_sync/src/Form/LdapDepartmentsSyncConfigForm.php
Normal file
1517
ldap_departments_sync/src/Form/LdapDepartmentsSyncConfigForm.php
Normal file
File diff suppressed because it is too large
Load Diff
1531
ldap_departments_sync/src/LdapDepartmentsSync.php
Normal file
1531
ldap_departments_sync/src/LdapDepartmentsSync.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ldap_departments_sync\Plugin\EntityReferenceSelection;
|
||||
|
||||
use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'department' entity_reference selection.
|
||||
*
|
||||
* @EntityReferenceSelection(
|
||||
* id = "ldap_departments_sync",
|
||||
* label = @Translation("Department selection"),
|
||||
* entity_types = {"group"},
|
||||
* group = "ldap_departments_sync",
|
||||
* weight = 1
|
||||
* )
|
||||
*/
|
||||
class DepartmentSelection extends DefaultSelection {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return [
|
||||
'filter_by_type' => FALSE,
|
||||
'allowed_types' => [],
|
||||
] + parent::defaultConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::buildConfigurationForm($form, $form_state);
|
||||
|
||||
// Força departments como bundle padrão
|
||||
$form['target_bundles']['#default_value'] = ['departments' => 'departments'];
|
||||
|
||||
$configuration = $this->getConfiguration();
|
||||
|
||||
$form['filter_by_type'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Filter by department type'),
|
||||
'#description' => $this->t('Only show departments of specific types (field_dept_type).'),
|
||||
'#default_value' => $configuration['filter_by_type'],
|
||||
'#weight' => 10,
|
||||
];
|
||||
|
||||
$form['allowed_types'] = [
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Allowed department types'),
|
||||
'#options' => [
|
||||
'academico' => $this->t('Acadêmico'),
|
||||
'administrativo' => $this->t('Administrativo'),
|
||||
],
|
||||
'#default_value' => $configuration['allowed_types'],
|
||||
'#weight' => 11,
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[name="settings[handler_settings][filter_by_type]"]' => ['checked' => TRUE],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::validateConfigurationForm($form, $form_state);
|
||||
|
||||
// Remove valores vazios de allowed_types
|
||||
$allowed_types = $form_state->getValue(['settings', 'handler_settings', 'allowed_types']);
|
||||
if (is_array($allowed_types)) {
|
||||
$allowed_types = array_filter($allowed_types);
|
||||
$form_state->setValue(['settings', 'handler_settings', 'allowed_types'], $allowed_types);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$query = parent::buildEntityQuery($match, $match_operator);
|
||||
|
||||
$configuration = $this->getConfiguration();
|
||||
|
||||
// Força apenas departments
|
||||
$query->condition('type', 'departments');
|
||||
|
||||
// Filtra por tipo de departamento se configurado
|
||||
if (!empty($configuration['filter_by_type']) && !empty($configuration['allowed_types'])) {
|
||||
$allowed_types = array_filter($configuration['allowed_types']);
|
||||
if (!empty($allowed_types)) {
|
||||
$query->condition('field_dept_type', array_keys($allowed_types), 'IN');
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
# Portuguese (Brazil) translation for LDAP Departments Sync module
|
||||
# Copyright (c) 2025
|
||||
# This file is distributed under the same license as the LDAP Departments Sync module.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: LDAP Departments Sync 1.0.0\n"
|
||||
"POT-Creation-Date: 2025-11-07 12:00+0000\n"
|
||||
"PO-Revision-Date: 2025-11-07 12:00+0000\n"
|
||||
"Language-Team: Portuguese (Brazil)\n"
|
||||
"Language: pt-br\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: src/Controller/LocalModulesController.php
|
||||
msgid "Local Modules"
|
||||
msgstr "Módulos Locais"
|
||||
|
||||
#: ldap_departments_sync.routing.yml
|
||||
msgid "LDAP Departments Sync"
|
||||
msgstr "Sincronização de Departamentos LDAP"
|
||||
|
||||
#: ldap_departments_sync.module
|
||||
msgid "This module synchronizes departments from an LDAP server to groups through cron."
|
||||
msgstr "Este módulo sincroniza departamentos de um servidor LDAP para grupos através do cron."
|
||||
|
||||
#: src/Form/LdapDepartmentsSyncConfigForm.php
|
||||
|
||||
msgid "Manage Fields"
|
||||
msgstr "Gerenciar Campos"
|
||||
|
||||
msgid "LDAP Server"
|
||||
msgstr "Servidor LDAP"
|
||||
|
||||
msgid "Select the LDAP server configured for departments synchronization."
|
||||
msgstr "Selecione o servidor LDAP configurado para sincronização de departamentos."
|
||||
|
||||
msgid "- Select a server -"
|
||||
msgstr "- Selecione um servidor -"
|
||||
|
||||
msgid "No LDAP server found. <a href=\"@url\">Configure an LDAP server</a> first."
|
||||
msgstr "Nenhum servidor LDAP encontrado. <a href=\"@url\">Configure um servidor LDAP</a> primeiro."
|
||||
|
||||
msgid "LDAP Query"
|
||||
msgstr "Consulta LDAP"
|
||||
|
||||
msgid "Select the LDAP query that will be used to search for departments."
|
||||
msgstr "Selecione a consulta LDAP que será usada para buscar departamentos."
|
||||
|
||||
msgid "- Select a query -"
|
||||
msgstr "- Selecione uma query -"
|
||||
|
||||
msgid "No LDAP query found for the selected server. <a href=\"@url\">Create a new LDAP query</a>."
|
||||
msgstr "Nenhuma query LDAP encontrada para o servidor selecionado. <a href=\"@url\">Crie uma nova query LDAP</a>."
|
||||
|
||||
msgid "Create New LDAP Query"
|
||||
msgstr "Criar Nova Query LDAP"
|
||||
|
||||
msgid "Edit Selected Query"
|
||||
msgstr "Editar Query Selecionada"
|
||||
|
||||
msgid "Hierarchy"
|
||||
msgstr "Hierarquia"
|
||||
|
||||
msgid "Configure whether departments should be organized hierarchically based on LDAP attributes."
|
||||
msgstr "Configure se os departamentos devem ser organizados hierarquicamente baseado em atributos LDAP."
|
||||
|
||||
msgid "Enable hierarchy"
|
||||
msgstr "Habilitar hierarquização"
|
||||
|
||||
msgid "When enabled, departments will be organized hierarchically based on the specified parent and child attributes."
|
||||
msgstr "Quando habilitado, os departamentos serão organizados hierarquicamente baseado nos atributos parent e child especificados."
|
||||
|
||||
msgid "Parent Attribute"
|
||||
msgstr "Atributo Pai"
|
||||
|
||||
msgid "LDAP attribute that contains the parent department code (e.g. departmentNumber)."
|
||||
msgstr "Atributo LDAP que contém o código do departamento pai (ex: departmentNumber)."
|
||||
|
||||
msgid "- Select an attribute -"
|
||||
msgstr "- Selecione um atributo -"
|
||||
|
||||
msgid "Child Attribute"
|
||||
msgstr "Atributo Filho"
|
||||
|
||||
msgid "LDAP attribute that contains the department's own code (e.g. imeccDepartmentCode)."
|
||||
msgstr "Atributo LDAP que contém o código próprio do departamento (ex: imeccDepartmentCode)."
|
||||
|
||||
msgid "All elements with the same child value will be nested under the corresponding parent recursively."
|
||||
msgstr "Todos os elementos com o mesmo valor de child serão aninhados sob o parent correspondente recursivamente."
|
||||
|
||||
msgid "Attribute Mapping"
|
||||
msgstr "Mapeamento de Atributos"
|
||||
|
||||
msgid "Configure how LDAP attributes are mapped to group fields.<br><strong>Note:</strong> For \"User Reference\" mappings, the search attribute will be automatically obtained from the \"Account name attribute\" field (or \"Authentication name attribute\" as fallback) configured in the selected LDAP server."
|
||||
msgstr "Configure como os atributos LDAP são mapeados para os campos do grupo.<br><strong>Nota:</strong> Para mapeamentos de \"Referência de Usuário\", o atributo de busca será automaticamente obtido do campo \"Account name attribute\" (ou \"Authentication name attribute\" como fallback) configurado no servidor LDAP selecionado."
|
||||
|
||||
msgid "Entity Field"
|
||||
msgstr "Campo da Entidade"
|
||||
|
||||
msgid "Group Field"
|
||||
msgstr "Campo do Grupo"
|
||||
|
||||
msgid "LDAP Attribute"
|
||||
msgstr "Atributo LDAP"
|
||||
|
||||
msgid "Mapping Type"
|
||||
msgstr "Tipo de Mapeamento"
|
||||
|
||||
msgid "Remove"
|
||||
msgstr "Remover"
|
||||
|
||||
msgid "No mappings configured."
|
||||
msgstr "Nenhum mapeamento configurado."
|
||||
|
||||
msgid "- Select a field -"
|
||||
msgstr "- Selecione um campo -"
|
||||
|
||||
msgid "Simple (text)"
|
||||
msgstr "Simples (texto)"
|
||||
|
||||
msgid "User Reference (DN → User)"
|
||||
msgstr "Referência de Usuário (DN → User)"
|
||||
|
||||
msgid "Add Mapping"
|
||||
msgstr "Adicionar Mapeamento"
|
||||
|
||||
msgid "Remove Selected"
|
||||
msgstr "Remover Selecionados"
|
||||
|
||||
msgid "Save Configuration"
|
||||
msgstr "Salvar Configurações"
|
||||
|
||||
msgid "Test Connection"
|
||||
msgstr "Testar Conexão"
|
||||
|
||||
msgid "Synchronize Departments"
|
||||
msgstr "Sincronizar Departamentos"
|
||||
|
||||
msgid "Error loading LDAP servers: @message"
|
||||
msgstr "Erro ao carregar servidores LDAP: @message"
|
||||
|
||||
msgid "Error loading group fields: @message"
|
||||
msgstr "Erro ao carregar campos do grupo: @message"
|
||||
|
||||
msgid "Error loading query attributes: @message"
|
||||
msgstr "Erro ao carregar atributos da query: @message"
|
||||
|
||||
msgid "LDAP attribute is required when field is selected."
|
||||
msgstr "Atributo LDAP é obrigatório quando campo está selecionado."
|
||||
|
||||
msgid "Group field is required when attribute is selected."
|
||||
msgstr "Campo do grupo é obrigatório quando atributo está selecionado."
|
||||
|
||||
msgid "Configuration saved successfully."
|
||||
msgstr "Configurações salvas com sucesso."
|
||||
|
||||
msgid "Group Role Mapping"
|
||||
msgstr "Mapeamento de Papéis em Grupos"
|
||||
|
||||
msgid "Configure how user attributes map to group roles. Each role can have its own mapping criteria."
|
||||
msgstr "Configure como atributos de usuário mapeiam para papéis em grupos. Cada papel pode ter seus próprios critérios de mapeamento."
|
||||
|
||||
msgid "Configure how to assign group roles based on LDAP attributes or user fields."
|
||||
msgstr "Configure como atribuir papéis em grupos baseado em atributos LDAP ou campos de usuário."
|
||||
|
||||
msgid "Enable role mapping"
|
||||
msgstr "Habilitar mapeamento de papéis"
|
||||
|
||||
msgid "When enabled, users will be assigned group roles based on the mappings below."
|
||||
msgstr "Quando habilitado, os usuários receberão papéis em grupos baseado nos mapeamentos abaixo."
|
||||
|
||||
msgid "Group Role"
|
||||
msgstr "Papel do Grupo"
|
||||
|
||||
msgid "Source"
|
||||
msgstr "Origem"
|
||||
|
||||
msgid "LDAP Attribute"
|
||||
msgstr "Atributo LDAP"
|
||||
|
||||
msgid "User Field"
|
||||
msgstr "Campo do Usuário"
|
||||
|
||||
msgid "Values (comma-separated)"
|
||||
msgstr "Valores (separados por vírgula)"
|
||||
|
||||
msgid "No role mappings configured."
|
||||
msgstr "Nenhum mapeamento de papel configurado."
|
||||
|
||||
msgid "- Select a role -"
|
||||
msgstr "- Selecione um papel -"
|
||||
|
||||
msgid "Add Role Mapping"
|
||||
msgstr "Adicionar Mapeamento de Papel"
|
||||
|
||||
msgid "Remove Selected"
|
||||
msgstr "Remover Selecionados"
|
||||
|
||||
msgid "Default Group Role"
|
||||
msgstr "Papel Padrão do Grupo"
|
||||
|
||||
msgid "The default role to assign if no role mapping matches."
|
||||
msgstr "O papel padrão a ser atribuído se nenhum mapeamento corresponder."
|
||||
|
||||
msgid "Enter the expected values for this field/attribute, separated by commas (e.g., admin,administrator,manager)."
|
||||
msgstr "Digite os valores esperados para este campo/atributo, separados por vírgula (ex: admin,administrador,gerente)."
|
||||
|
||||
msgid "Internal"
|
||||
msgstr "Interno"
|
||||
|
||||
msgid "Outsider"
|
||||
msgstr "Externo"
|
||||
|
||||
msgid "- Select attribute/field -"
|
||||
msgstr "- Selecione atributo/campo -"
|
||||
|
||||
msgid "Group Field Match"
|
||||
msgstr "Correspondência de Campo do Grupo"
|
||||
|
||||
msgid "User Field / LDAP Attribute"
|
||||
msgstr "Campo do Usuário / Atributo LDAP"
|
||||
|
||||
msgid "Group Field / Values"
|
||||
msgstr "Campo do Grupo / Valores"
|
||||
|
||||
msgid "- Select group field -"
|
||||
msgstr "- Selecione campo do grupo -"
|
||||
|
||||
msgid "- Select user field -"
|
||||
msgstr "- Selecione campo do usuário -"
|
||||
|
||||
msgid "The default \"departments\" group type is not installed."
|
||||
msgstr "O tipo de grupo padrão \"departments\" não está instalado."
|
||||
|
||||
msgid "Install Default Configuration"
|
||||
msgstr "Instalar Configuração Padrão"
|
||||
|
||||
msgid "The button above will create:<ul><li>Group type \"departments\" with all required fields</li><li>User fields for department synchronization</li><li>Default group roles and displays</li></ul>Or you can <a href=\"@url\">create a custom group type</a> manually."
|
||||
msgstr "O botão acima irá criar:<ul><li>Tipo de grupo \"departments\" com todos os campos necessários</li><li>Campos de usuário para sincronização de departamento</li><li>Papéis e visualizações de grupo padrão</li></ul>Ou você pode <a href=\"@url\">criar um tipo de grupo personalizado</a> manualmente."
|
||||
|
||||
msgid "Successfully installed @count configuration items. Group type \"departments\" and all required fields have been created. Please reload the page to see the changes."
|
||||
msgstr "@count itens de configuração instalados com sucesso. O tipo de grupo \"departments\" e todos os campos necessários foram criados. Por favor, recarregue a página para ver as alterações."
|
||||
|
||||
msgid "All configurations already exist. Nothing was imported."
|
||||
msgstr "Todas as configurações já existem. Nada foi importado."
|
||||
|
||||
msgid "Error installing default configuration: @message"
|
||||
msgstr "Erro ao instalar configuração padrão: @message"
|
||||
|
||||
msgid "Configuration directory not found: @path"
|
||||
msgstr "Diretório de configuração não encontrado: @path"
|
||||
|
||||
msgid "Configuration @name already exists, skipping."
|
||||
msgstr "Configuração @name já existe, ignorando."
|
||||
|
||||
#: src/Plugin/EntityReferenceSelection/DepartmentSelection.php
|
||||
msgid "Filter by department type"
|
||||
msgstr "Filtrar por tipo de departamento"
|
||||
|
||||
msgid "Only show departments of specific types (field_dept_type)."
|
||||
msgstr "Mostrar apenas departamentos de tipos específicos (field_dept_type)."
|
||||
|
||||
msgid "Allowed department types"
|
||||
msgstr "Tipos de departamento permitidos"
|
||||
|
||||
msgid "Acadêmico"
|
||||
msgstr "Acadêmico"
|
||||
|
||||
msgid "Administrativo"
|
||||
msgstr "Administrativo"
|
||||
|
||||
msgid "Department selection"
|
||||
msgstr "Seleção de departamento"
|
||||
|
||||
#: ldap_departments_sync.links.task.yml
|
||||
msgid "Configuration"
|
||||
msgstr "Configuração"
|
||||
|
||||
msgid "Access Rules"
|
||||
msgstr "Regras de Acesso"
|
||||
|
||||
msgid "Access Rule"
|
||||
msgstr "Regra de Acesso"
|
||||
152
ldap_departments_sync/translations/pt-br.po
Normal file
152
ldap_departments_sync/translations/pt-br.po
Normal file
@@ -0,0 +1,152 @@
|
||||
# Portuguese translation of LDAP Departments Sync
|
||||
# Copyright (c) 2025
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: LDAP Departments Sync 1.0.0\n"
|
||||
"POT-Creation-Date: 2025-01-12 10:00-0300\n"
|
||||
"PO-Revision-Date: 2025-01-12 10:00-0300\n"
|
||||
"Language-Team: Portuguese (Brazil)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"Language: pt_BR\n"
|
||||
|
||||
# Form titles and sections
|
||||
msgid "Synchronization Type"
|
||||
msgstr "Tipo de Sincronização"
|
||||
|
||||
msgid "Data storage type"
|
||||
msgstr "Tipo de armazenamento de dados"
|
||||
|
||||
msgid "Choose whether departments should be synchronized as taxonomy terms or as groups."
|
||||
msgstr "Escolha se os departamentos devem ser sincronizados como termos de taxonomia ou como grupos."
|
||||
|
||||
msgid "Taxonomy Vocabulary - Store departments as taxonomy terms"
|
||||
msgstr "Vocabulário de Taxonomia - Armazenar departamentos como termos de taxonomia"
|
||||
|
||||
msgid "Groups - Store departments as group entities"
|
||||
msgstr "Grupos - Armazenar departamentos como entidades de grupo"
|
||||
|
||||
msgid "Updating form..."
|
||||
msgstr "Atualizando formulário..."
|
||||
|
||||
msgid "Taxonomy Vocabulary"
|
||||
msgstr "Vocabulário de Taxonomia"
|
||||
|
||||
msgid "Target Vocabulary"
|
||||
msgstr "Vocabulário de Destino"
|
||||
|
||||
msgid "Select the taxonomy vocabulary where departments will be synchronized. <br><strong>Required fields:</strong> field_dept_code, field_dept_acronym, field_dept_type, field_dept_phone, field_dept_room, field_dept_mail"
|
||||
msgstr "Selecione o vocabulário de taxonomia onde os departamentos serão sincronizados. <br><strong>Campos obrigatórios:</strong> field_dept_code, field_dept_acronym, field_dept_type, field_dept_phone, field_dept_room, field_dept_mail"
|
||||
|
||||
msgid "- Select a vocabulary -"
|
||||
msgstr "- Selecione um vocabulário -"
|
||||
|
||||
msgid "No taxonomy vocabulary found. <a href=\"@url\">Create a vocabulary</a> first."
|
||||
msgstr "Nenhum vocabulário de taxonomia encontrado. <a href=\"@url\">Crie um vocabulário</a> primeiro."
|
||||
|
||||
msgid "Create New Vocabulary"
|
||||
msgstr "Criar Novo Vocabulário"
|
||||
|
||||
msgid "Manage Vocabulary"
|
||||
msgstr "Gerenciar Vocabulário"
|
||||
|
||||
msgid "Manage Fields"
|
||||
msgstr "Gerenciar Campos"
|
||||
|
||||
msgid "Group Type"
|
||||
msgstr "Tipo de Grupo"
|
||||
|
||||
msgid "Target Group Type"
|
||||
msgstr "Tipo de Grupo de Destino"
|
||||
|
||||
msgid "Select the group type where departments will be synchronized. <br><strong>Required fields:</strong> field_dept_code, field_dept_acronym, field_dept_type, field_dept_phone, field_dept_room, field_dept_mail"
|
||||
msgstr "Selecione o tipo de grupo onde os departamentos serão sincronizados. <br><strong>Campos obrigatórios:</strong> field_dept_code, field_dept_acronym, field_dept_type, field_dept_phone, field_dept_room, field_dept_mail"
|
||||
|
||||
msgid "- Select a group type -"
|
||||
msgstr "- Selecione um tipo de grupo -"
|
||||
|
||||
msgid "No group type found. <a href=\"@url\">Create a group type</a> first."
|
||||
msgstr "Nenhum tipo de grupo encontrado. <a href=\"@url\">Crie um tipo de grupo</a> primeiro."
|
||||
|
||||
msgid "Create New Group Type"
|
||||
msgstr "Criar Novo Tipo de Grupo"
|
||||
|
||||
msgid "Manage Group Type"
|
||||
msgstr "Gerenciar Tipo de Grupo"
|
||||
|
||||
msgid "LDAP Server"
|
||||
msgstr "Servidor LDAP"
|
||||
|
||||
msgid "Select the LDAP server configured for departments synchronization."
|
||||
msgstr "Selecione o servidor LDAP configurado para sincronização de departamentos."
|
||||
|
||||
msgid "- Select a server -"
|
||||
msgstr "- Selecione um servidor -"
|
||||
|
||||
msgid "No LDAP server found. <a href=\"@url\">Configure an LDAP server</a> first."
|
||||
msgstr "Nenhum servidor LDAP encontrado. <a href=\"@url\">Configure um servidor LDAP</a> primeiro."
|
||||
|
||||
msgid "LDAP Query"
|
||||
msgstr "Consulta LDAP"
|
||||
|
||||
msgid "Select the LDAP query that will be used to search for departments."
|
||||
msgstr "Selecione a consulta LDAP que será usada para buscar departamentos."
|
||||
|
||||
msgid "- Select a query -"
|
||||
msgstr "- Selecione uma consulta -"
|
||||
|
||||
msgid "No LDAP query found for the selected server. <a href=\"@url\">Create a new LDAP query</a>."
|
||||
msgstr "Nenhuma consulta LDAP encontrada para o servidor selecionado. <a href=\"@url\">Crie uma nova consulta LDAP</a>."
|
||||
|
||||
msgid "Create New LDAP Query"
|
||||
msgstr "Criar Nova Consulta LDAP"
|
||||
|
||||
msgid "Edit Selected Query"
|
||||
msgstr "Editar Consulta Selecionada"
|
||||
|
||||
msgid "Hierarchy"
|
||||
msgstr "Hierarquia"
|
||||
|
||||
msgid "Configure whether departments should be organized hierarchically based on LDAP attributes."
|
||||
msgstr "Configure se os departamentos devem ser organizados hierarquicamente com base em atributos LDAP."
|
||||
|
||||
msgid "Enable hierarchy"
|
||||
msgstr "Habilitar hierarquia"
|
||||
|
||||
msgid "When enabled, terms will be organized hierarchically based on the specified parent and child attributes."
|
||||
msgstr "Quando habilitado, os departamentos serão organizados hierarquicamente com base nos atributos de pai e filho especificados."
|
||||
|
||||
msgid "Parent Attribute"
|
||||
msgstr "Atributo Pai"
|
||||
|
||||
msgid "LDAP attribute that contains the parent department code (e.g. departmentNumber)."
|
||||
msgstr "Atributo LDAP que contém o código do departamento pai (ex: departmentNumber)."
|
||||
|
||||
msgid "Child Attribute"
|
||||
msgstr "Atributo Filho"
|
||||
|
||||
msgid "LDAP attribute that contains the department's own code (e.g. imeccDepartmentCode)."
|
||||
msgstr "Atributo LDAP que contém o código próprio do departamento (ex: imeccDepartmentCode)."
|
||||
|
||||
msgid "- Select an attribute -"
|
||||
msgstr "- Selecione um atributo -"
|
||||
|
||||
msgid "All elements with the same child value will be nested under the corresponding parent recursively."
|
||||
msgstr "Todos os elementos com o mesmo valor filho serão aninhados sob o pai correspondente recursivamente."
|
||||
|
||||
msgid "Attribute Mapping"
|
||||
msgstr "Mapeamento de Atributos"
|
||||
|
||||
msgid "Configure how LDAP attributes are mapped to target entity fields.<br><strong>Note:</strong> For \"User Reference\" mappings, the search attribute will be automatically obtained from the \"Account name attribute\" field (or \"Authentication name attribute\" as fallback) configured in the selected LDAP server."
|
||||
msgstr "Configure como os atributos LDAP são mapeados para os campos da entidade de destino.<br><strong>Nota:</strong> Para mapeamentos de \"Referência de Usuário\", o atributo de busca será obtido automaticamente do campo \"Account name attribute\" (ou \"Authentication name attribute\" como alternativa) configurado no servidor LDAP selecionado."
|
||||
|
||||
msgid "- Select a field -"
|
||||
msgstr "- Selecione um campo -"
|
||||
|
||||
msgid "Simple (text)"
|
||||
msgstr "Simples (texto)"
|
||||
|
||||
msgid "User Reference (DN → User)"
|
||||
msgstr "Referência de Usuário (DN → Usuário)"
|
||||
11
ldap_groups_sync.info.yml
Normal file
11
ldap_groups_sync.info.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
name: LDAP Groups Sync
|
||||
type: module
|
||||
description: 'Base module with shared access-rules infrastructure for LDAP group sync modules.'
|
||||
core_version_requirement: ^11
|
||||
package: Custom
|
||||
dependencies:
|
||||
- drupal:options
|
||||
- drupal:telephone
|
||||
- group:group
|
||||
- ldap:ldap_servers
|
||||
- site_tools
|
||||
69
ldap_research_groups_sync/README.md
Normal file
69
ldap_research_groups_sync/README.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# LDAP Research Groups Sync
|
||||
|
||||
Módulo Drupal 11 que sincroniza grupos de pesquisa do servidor LDAP corporativo com entidades do tipo `research_group` (módulo Group).
|
||||
|
||||
## Funcionalidades
|
||||
|
||||
- Criação e atualização automática de grupos de pesquisa via cron a partir de uma LDAP query configurável
|
||||
- Sincronização de membros dos grupos a partir do atributo `member` (ou outro configurável) de cada entrada LDAP
|
||||
- Regras de acesso configuráveis por grupo
|
||||
- Proteção dos campos LDAP do usuário contra edição não autorizada
|
||||
|
||||
## Dependências
|
||||
|
||||
- `drupal:options`
|
||||
- `drupal:telephone`
|
||||
- `group:group`
|
||||
- `ldap:ldap_servers`
|
||||
- `site_tools`
|
||||
|
||||
## Campos criados
|
||||
|
||||
### No grupo (`research_group`)
|
||||
|
||||
| Campo | Tipo | Descrição |
|
||||
|---|---|---|
|
||||
| `field_rg_code` | String | Código do grupo (chave de sincronização) |
|
||||
| `field_rg_phone` | Telephone | Telefone |
|
||||
| `field_rg_mail` | Email | E-mail |
|
||||
| `field_rg_coord` | Entity reference (user) | Coordenador do grupo |
|
||||
| `field_rg_coord_assoc` | Entity reference (user) | Coordenador associado do grupo |
|
||||
| `field_rg_department` | Entity reference (group) | Departamento ao qual o grupo está vinculado |
|
||||
|
||||
### No usuário
|
||||
|
||||
| Campo | Tipo | Descrição |
|
||||
|---|---|---|
|
||||
| `field_user_research_groups` | Entity reference (group, múltiplos) | Grupos de pesquisa do usuário (populado pelo sync) |
|
||||
|
||||
## Instalação
|
||||
|
||||
```bash
|
||||
drush en ldap_research_groups_sync
|
||||
drush cr
|
||||
```
|
||||
|
||||
## Configuração
|
||||
|
||||
Acesse `/admin/config/local-modules/ldap-research-groups-sync` e configure:
|
||||
|
||||
1. **Group Type** — selecione `research_group`
|
||||
2. **LDAP Server** — servidor LDAP a ser usado
|
||||
3. **LDAP Query** — query entity que retorna as entradas dos grupos de pesquisa
|
||||
4. **Attribute Mappings** — mapeamento entre atributos LDAP e campos do grupo
|
||||
5. **Member Synchronization** — habilite e defina o atributo LDAP de membros (padrão: `member`)
|
||||
|
||||
> **Atenção:** o atributo de membros (ex.: `member`) deve estar incluído nos atributos retornados pela LDAP query, ou a query não deve ter filtro de atributos.
|
||||
|
||||
## Sincronização manual
|
||||
|
||||
```bash
|
||||
drush php-eval "\Drupal::service('ldap_research_groups_sync.sync')->syncResearchGroups();"
|
||||
```
|
||||
|
||||
A sincronização também é executada automaticamente pelo cron.
|
||||
|
||||
## Permissões
|
||||
|
||||
- `administer ldap research groups sync` — acesso à página de configuração
|
||||
- `edit ldap managed user rg fields` — permite editar o campo `field_user_research_groups` manualmente (normalmente reservado ao sync)
|
||||
@@ -0,0 +1,102 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.group.research_group.field_rg_code
|
||||
- field.field.group.research_group.field_rg_coord
|
||||
- field.field.group.research_group.field_rg_coord_assoc
|
||||
- field.field.group.research_group.field_rg_mail
|
||||
- field.field.group.research_group.field_rg_phone
|
||||
- field.field.group.research_group.field_rg_department
|
||||
- group.type.research_group
|
||||
module:
|
||||
- path
|
||||
id: group.research_group.default
|
||||
targetEntityType: group
|
||||
bundle: research_group
|
||||
mode: default
|
||||
content:
|
||||
field_rg_code:
|
||||
type: string_textfield
|
||||
weight: 122
|
||||
region: content
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_rg_mail:
|
||||
type: email_default
|
||||
weight: 125
|
||||
region: content
|
||||
settings:
|
||||
placeholder: ''
|
||||
size: 60
|
||||
third_party_settings: { }
|
||||
field_rg_phone:
|
||||
type: string_textfield
|
||||
weight: 124
|
||||
region: content
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_rg_coord:
|
||||
type: entity_reference_autocomplete
|
||||
weight: 126
|
||||
region: content
|
||||
settings:
|
||||
match_operator: CONTAINS
|
||||
match_limit: 10
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_rg_coord_assoc:
|
||||
type: entity_reference_autocomplete
|
||||
weight: 127
|
||||
region: content
|
||||
settings:
|
||||
match_operator: CONTAINS
|
||||
match_limit: 10
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_rg_department:
|
||||
type: entity_reference_autocomplete
|
||||
weight: 25
|
||||
region: content
|
||||
settings:
|
||||
match_operator: CONTAINS
|
||||
match_limit: 10
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
label:
|
||||
type: string_textfield
|
||||
weight: -5
|
||||
region: content
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
langcode:
|
||||
type: language_select
|
||||
weight: 2
|
||||
region: content
|
||||
settings:
|
||||
include_locked: true
|
||||
third_party_settings: { }
|
||||
path:
|
||||
type: path
|
||||
weight: 30
|
||||
region: content
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
status:
|
||||
type: boolean_checkbox
|
||||
weight: 120
|
||||
region: content
|
||||
settings:
|
||||
display_label: true
|
||||
third_party_settings: { }
|
||||
hidden:
|
||||
uid: true
|
||||
@@ -0,0 +1,81 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.group.research_group.field_rg_code
|
||||
- field.field.group.research_group.field_rg_coord
|
||||
- field.field.group.research_group.field_rg_coord_assoc
|
||||
- field.field.group.research_group.field_rg_mail
|
||||
- field.field.group.research_group.field_rg_phone
|
||||
- field.field.group.research_group.field_rg_department
|
||||
- group.type.research_group
|
||||
module:
|
||||
- options
|
||||
id: group.research_group.default
|
||||
targetEntityType: group
|
||||
bundle: research_group
|
||||
mode: default
|
||||
content:
|
||||
field_rg_code:
|
||||
type: string
|
||||
label: above
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
weight: -3
|
||||
region: content
|
||||
field_rg_mail:
|
||||
type: basic_string
|
||||
label: above
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
weight: 0
|
||||
region: content
|
||||
field_rg_phone:
|
||||
type: string
|
||||
label: above
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
weight: -1
|
||||
region: content
|
||||
field_rg_coord:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 1
|
||||
region: content
|
||||
field_rg_coord_assoc:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 2
|
||||
region: content
|
||||
field_rg_department:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 25
|
||||
region: content
|
||||
label:
|
||||
type: string
|
||||
label: hidden
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
weight: -5
|
||||
region: content
|
||||
hidden:
|
||||
changed: true
|
||||
created: true
|
||||
entity_print_view_epub: true
|
||||
entity_print_view_pdf: true
|
||||
entity_print_view_word_docx: true
|
||||
langcode: true
|
||||
uid: true
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_rg_code
|
||||
- group.type.research_group
|
||||
id: group.research_group.field_rg_code
|
||||
field_name: field_rg_code
|
||||
entity_type: group
|
||||
bundle: research_group
|
||||
label: 'Código'
|
||||
description: 'Código do grupo de pesquisa (chave de sincronização LDAP)'
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: string
|
||||
@@ -0,0 +1,30 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_rg_coord
|
||||
- group.type.research_group
|
||||
module:
|
||||
- user
|
||||
id: group.research_group.field_rg_coord
|
||||
field_name: field_rg_coord
|
||||
entity_type: group
|
||||
bundle: research_group
|
||||
label: Coordenador
|
||||
description: 'Usuário responsável pela coordenação do grupo de pesquisa'
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: 'default:user'
|
||||
handler_settings:
|
||||
target_bundles: null
|
||||
sort:
|
||||
field: _none
|
||||
direction: ASC
|
||||
auto_create: false
|
||||
filter:
|
||||
type: _none
|
||||
include_anonymous: false
|
||||
field_type: entity_reference
|
||||
@@ -0,0 +1,30 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_rg_coord_assoc
|
||||
- group.type.research_group
|
||||
module:
|
||||
- user
|
||||
id: group.research_group.field_rg_coord_assoc
|
||||
field_name: field_rg_coord_assoc
|
||||
entity_type: group
|
||||
bundle: research_group
|
||||
label: 'Coordenador Associado'
|
||||
description: 'Usuário responsável pela coordenação associada do grupo de pesquisa'
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: 'default:user'
|
||||
handler_settings:
|
||||
target_bundles: null
|
||||
sort:
|
||||
field: _none
|
||||
direction: ASC
|
||||
auto_create: false
|
||||
filter:
|
||||
type: _none
|
||||
include_anonymous: false
|
||||
field_type: entity_reference
|
||||
@@ -0,0 +1,28 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_rg_department
|
||||
- group.type.department
|
||||
- group.type.research_group
|
||||
id: group.research_group.field_rg_department
|
||||
field_name: field_rg_department
|
||||
entity_type: group
|
||||
bundle: research_group
|
||||
label: Departamento
|
||||
description: 'Departamento ao qual este grupo de pesquisa está vinculado'
|
||||
required: false
|
||||
translatable: true
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: 'default:group'
|
||||
handler_settings:
|
||||
target_bundles:
|
||||
department: department
|
||||
sort:
|
||||
field: _none
|
||||
direction: ASC
|
||||
auto_create: false
|
||||
auto_create_bundle: ''
|
||||
field_type: entity_reference
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_rg_mail
|
||||
- group.type.research_group
|
||||
id: group.research_group.field_rg_mail
|
||||
field_name: field_rg_mail
|
||||
entity_type: group
|
||||
bundle: research_group
|
||||
label: 'E-mail'
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: email
|
||||
@@ -0,0 +1,20 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.group.field_rg_phone
|
||||
- group.type.research_group
|
||||
module:
|
||||
- telephone
|
||||
id: group.research_group.field_rg_phone
|
||||
field_name: field_rg_phone
|
||||
entity_type: group
|
||||
bundle: research_group
|
||||
label: 'Telefone'
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: telephone
|
||||
@@ -0,0 +1,28 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.user.field_user_research_groups
|
||||
module:
|
||||
- user
|
||||
id: user.user.field_user_research_groups
|
||||
field_name: field_user_research_groups
|
||||
entity_type: user
|
||||
bundle: user
|
||||
label: 'Grupos de Pesquisa'
|
||||
description: 'Grupos de pesquisa do usuário sincronizados do LDAP'
|
||||
required: false
|
||||
translatable: true
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: 'default:group'
|
||||
handler_settings:
|
||||
target_bundles:
|
||||
research_group: research_group
|
||||
sort:
|
||||
field: _none
|
||||
direction: ASC
|
||||
auto_create: false
|
||||
auto_create_bundle: ''
|
||||
field_type: entity_reference
|
||||
@@ -0,0 +1,20 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
id: group.field_rg_code
|
||||
field_name: field_rg_code
|
||||
entity_type: group
|
||||
type: string
|
||||
settings:
|
||||
max_length: 255
|
||||
case_sensitive: false
|
||||
is_ascii: false
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,19 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
- user
|
||||
id: group.field_rg_coord
|
||||
field_name: field_rg_coord
|
||||
entity_type: group
|
||||
type: entity_reference
|
||||
settings:
|
||||
target_type: user
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,19 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
- user
|
||||
id: group.field_rg_coord_assoc
|
||||
field_name: field_rg_coord_assoc
|
||||
entity_type: group
|
||||
type: entity_reference
|
||||
settings:
|
||||
target_type: user
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
id: group.field_rg_department
|
||||
field_name: field_rg_department
|
||||
entity_type: group
|
||||
type: entity_reference
|
||||
settings:
|
||||
target_type: group
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,17 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
id: group.field_rg_mail
|
||||
field_name: field_rg_mail
|
||||
entity_type: group
|
||||
type: email
|
||||
settings: { }
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,18 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
- telephone
|
||||
id: group.field_rg_phone
|
||||
field_name: field_rg_phone
|
||||
entity_type: group
|
||||
type: telephone
|
||||
settings: { }
|
||||
module: telephone
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,19 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- group
|
||||
- user
|
||||
id: user.field_user_research_groups
|
||||
field_name: field_user_research_groups
|
||||
entity_type: user
|
||||
type: entity_reference
|
||||
settings:
|
||||
target_type: group
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: -1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,37 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.research_group
|
||||
id: research_group-admin
|
||||
label: Admin
|
||||
weight: 100
|
||||
admin: true
|
||||
scope: individual
|
||||
global_role: null
|
||||
group_type: research_group
|
||||
permissions:
|
||||
- administer members
|
||||
- delete group
|
||||
- edit group
|
||||
- leave group
|
||||
- view group
|
||||
- view unpublished group
|
||||
- access group_media overview
|
||||
- access group_node overview
|
||||
- create group_node:article entity
|
||||
- create group_node:page entity
|
||||
- delete any group_node:article entity
|
||||
- delete any group_node:page entity
|
||||
- delete own group_node:article entity
|
||||
- delete own group_node:page entity
|
||||
- update any group_node:article entity
|
||||
- update any group_node:page entity
|
||||
- update own group_node:article entity
|
||||
- update own group_node:page entity
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
- view own unpublished group_node:article entity
|
||||
- view own unpublished group_node:page entity
|
||||
- view unpublished group_node:article entity
|
||||
- view unpublished group_node:page entity
|
||||
@@ -0,0 +1,38 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.research_group
|
||||
- user.role.administrator
|
||||
id: research_group-admin_in
|
||||
label: Administrador
|
||||
weight: 102
|
||||
admin: true
|
||||
scope: insider
|
||||
global_role: administrator
|
||||
group_type: research_group
|
||||
permissions:
|
||||
- administer members
|
||||
- delete group
|
||||
- edit group
|
||||
- leave group
|
||||
- view group
|
||||
- view unpublished group
|
||||
- access group_media overview
|
||||
- access group_node overview
|
||||
- create group_node:article entity
|
||||
- create group_node:page entity
|
||||
- delete any group_node:article entity
|
||||
- delete any group_node:page entity
|
||||
- delete own group_node:article entity
|
||||
- delete own group_node:page entity
|
||||
- update any group_node:article entity
|
||||
- update any group_node:page entity
|
||||
- update own group_node:article entity
|
||||
- update own group_node:page entity
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
- view own unpublished group_node:article entity
|
||||
- view own unpublished group_node:page entity
|
||||
- view unpublished group_node:article entity
|
||||
- view unpublished group_node:page entity
|
||||
@@ -0,0 +1,38 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.research_group
|
||||
- user.role.administrator
|
||||
id: research_group-admin_out
|
||||
label: Administrador
|
||||
weight: 101
|
||||
admin: true
|
||||
scope: outsider
|
||||
global_role: administrator
|
||||
group_type: research_group
|
||||
permissions:
|
||||
- administer members
|
||||
- delete group
|
||||
- edit group
|
||||
- join group
|
||||
- view group
|
||||
- view unpublished group
|
||||
- access group_media overview
|
||||
- access group_node overview
|
||||
- create group_node:article entity
|
||||
- create group_node:page entity
|
||||
- delete any group_node:article entity
|
||||
- delete any group_node:page entity
|
||||
- delete own group_node:article entity
|
||||
- delete own group_node:page entity
|
||||
- update any group_node:article entity
|
||||
- update any group_node:page entity
|
||||
- update own group_node:article entity
|
||||
- update own group_node:page entity
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
- view own unpublished group_node:article entity
|
||||
- view own unpublished group_node:page entity
|
||||
- view unpublished group_node:article entity
|
||||
- view unpublished group_node:page entity
|
||||
@@ -0,0 +1,17 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.research_group
|
||||
- user.role.anonymous
|
||||
id: research_group-anonymous
|
||||
label: 'Anônimo'
|
||||
weight: -102
|
||||
admin: false
|
||||
scope: outsider
|
||||
global_role: anonymous
|
||||
group_type: research_group
|
||||
permissions:
|
||||
- view group
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
@@ -0,0 +1,27 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.research_group
|
||||
- user.role.authenticated
|
||||
id: research_group-member
|
||||
label: Member
|
||||
weight: -100
|
||||
admin: false
|
||||
scope: insider
|
||||
global_role: authenticated
|
||||
group_type: research_group
|
||||
permissions:
|
||||
- view group
|
||||
- access group_media overview
|
||||
- access group_node overview
|
||||
- create group_node:article entity
|
||||
- create group_node:page entity
|
||||
- delete own group_node:article entity
|
||||
- delete own group_node:page entity
|
||||
- update own group_node:article entity
|
||||
- update own group_node:page entity
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
- view own unpublished group_node:article entity
|
||||
- view own unpublished group_node:page entity
|
||||
@@ -0,0 +1,17 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- group.type.research_group
|
||||
- user.role.authenticated
|
||||
id: research_group-outsider
|
||||
label: Outsider
|
||||
weight: -101
|
||||
admin: false
|
||||
scope: outsider
|
||||
global_role: authenticated
|
||||
group_type: research_group
|
||||
permissions:
|
||||
- view group
|
||||
- view group_node:article entity
|
||||
- view group_node:page entity
|
||||
@@ -0,0 +1,10 @@
|
||||
langcode: pt-br
|
||||
status: true
|
||||
dependencies: { }
|
||||
id: research_group
|
||||
label: 'Grupo de Pesquisa'
|
||||
description: ''
|
||||
new_revision: true
|
||||
creator_membership: true
|
||||
creator_wizard: true
|
||||
creator_roles: { }
|
||||
73
ldap_research_groups_sync/css/role-mapping.css
Normal file
73
ldap_research_groups_sync/css/role-mapping.css
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Role mapping table styles
|
||||
*/
|
||||
|
||||
/* Limita a largura da tabela e permite scroll horizontal se necessário */
|
||||
.role-mappings-table {
|
||||
max-width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
/* Define larguras fixas para cada coluna */
|
||||
.role-mappings-table th:nth-child(1),
|
||||
.role-mappings-table td:nth-child(1) {
|
||||
width: 20%;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.role-mappings-table th:nth-child(2),
|
||||
.role-mappings-table td:nth-child(2) {
|
||||
width: 15%;
|
||||
min-width: 130px;
|
||||
}
|
||||
|
||||
.role-mappings-table th:nth-child(3),
|
||||
.role-mappings-table td:nth-child(3) {
|
||||
width: 25%;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.role-mappings-table th:nth-child(4),
|
||||
.role-mappings-table td:nth-child(4) {
|
||||
width: 30%;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.role-mappings-table th:nth-child(5),
|
||||
.role-mappings-table td:nth-child(5) {
|
||||
width: 10%;
|
||||
min-width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Estilo dos selects para limitar largura e truncar texto */
|
||||
.role-mapping-field-select {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Estilo para options dentro dos selects - mostra texto completo no dropdown */
|
||||
.role-mapping-field-select option {
|
||||
white-space: normal;
|
||||
overflow: visible;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
/* Estilo do textarea */
|
||||
.role-mapping-values-textarea {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
/* Responsividade: em telas menores, permite scroll horizontal */
|
||||
@media (max-width: 1200px) {
|
||||
.role-mappings-table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
13
ldap_research_groups_sync/ldap_research_groups_sync.info.yml
Normal file
13
ldap_research_groups_sync/ldap_research_groups_sync.info.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
name: LDAP Research Groups Sync
|
||||
type: module
|
||||
description: 'Sincroniza grupos de pesquisa do servidor LDAP com grupos via cron'
|
||||
version: '1.0.0'
|
||||
core_version_requirement: ^11
|
||||
package: Custom
|
||||
dependencies:
|
||||
- ldap_groups_sync:ldap_groups_sync
|
||||
- drupal:options
|
||||
- drupal:telephone
|
||||
- group:group
|
||||
- ldap:ldap_servers
|
||||
- site_tools
|
||||
94
ldap_research_groups_sync/ldap_research_groups_sync.install
Normal file
94
ldap_research_groups_sync/ldap_research_groups_sync.install
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Arquivo de instalação para ldap_research_groups_sync.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function ldap_research_groups_sync_install() {
|
||||
\Drupal::messenger()->addWarning(t('Please ensure your group type has the required fields: field_rg_code, field_rg_phone, field_rg_mail, and field_rg_department (for department reference).'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adiciona os campos field_rg_coord e field_rg_coord_assoc ao bundle research_group.
|
||||
*/
|
||||
function ldap_research_groups_sync_update_10001() {
|
||||
$configs = [
|
||||
'field.storage.group.field_rg_coord',
|
||||
'field.storage.group.field_rg_coord_assoc',
|
||||
'field.field.group.research_group.field_rg_coord',
|
||||
'field.field.group.research_group.field_rg_coord_assoc',
|
||||
];
|
||||
|
||||
$module_path = \Drupal::service('extension.list.module')->getPath('ldap_research_groups_sync');
|
||||
$config_path = $module_path . '/config/optional';
|
||||
$config_factory = \Drupal::configFactory();
|
||||
$yaml_parser = \Drupal::service('serialization.yaml');
|
||||
$imported = 0;
|
||||
|
||||
foreach ($configs as $config_name) {
|
||||
if (!$config_factory->get($config_name)->isNew()) {
|
||||
continue;
|
||||
}
|
||||
$file = $config_path . '/' . $config_name . '.yml';
|
||||
$data = $yaml_parser->decode(file_get_contents($file));
|
||||
$config_factory->getEditable($config_name)->setData($data)->save();
|
||||
$imported++;
|
||||
}
|
||||
|
||||
if ($imported > 0) {
|
||||
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
|
||||
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||
}
|
||||
|
||||
return t('Campos field_rg_coord e field_rg_coord_assoc importados (@count configs).', ['@count' => $imported]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adiciona o campo field_rg_code ao bundle research_group.
|
||||
*/
|
||||
function ldap_research_groups_sync_update_10002() {
|
||||
$configs = [
|
||||
'field.storage.group.field_rg_code',
|
||||
'field.field.group.research_group.field_rg_code',
|
||||
];
|
||||
|
||||
$module_path = \Drupal::service('extension.list.module')->getPath('ldap_research_groups_sync');
|
||||
$config_path = $module_path . '/config/optional';
|
||||
$config_factory = \Drupal::configFactory();
|
||||
$yaml_parser = \Drupal::service('serialization.yaml');
|
||||
$imported = 0;
|
||||
|
||||
foreach ($configs as $config_name) {
|
||||
if (!$config_factory->get($config_name)->isNew()) {
|
||||
continue;
|
||||
}
|
||||
$file = $config_path . '/' . $config_name . '.yml';
|
||||
$data = $yaml_parser->decode(file_get_contents($file));
|
||||
$config_factory->getEditable($config_name)->setData($data)->save();
|
||||
$imported++;
|
||||
}
|
||||
|
||||
if ($imported > 0) {
|
||||
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
|
||||
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||
}
|
||||
|
||||
return t('Campo field_rg_code importado (@count configs).', ['@count' => $imported]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function ldap_research_groups_sync_uninstall() {
|
||||
// Remove configurações
|
||||
\Drupal::configFactory()->getEditable('ldap_research_groups_sync.settings')->delete();
|
||||
|
||||
\Drupal::messenger()->addStatus(t('LDAP Research Groups Sync module uninstalled.'));
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
role_mapping_styles:
|
||||
version: 1.x
|
||||
css:
|
||||
theme:
|
||||
css/role-mapping.css: {}
|
||||
@@ -0,0 +1,6 @@
|
||||
ldap_research_groups_sync.config:
|
||||
title: 'LDAP Research Groups Sync'
|
||||
description: 'Configurar sincronização de grupos de pesquisa do LDAP'
|
||||
route_name: ldap_research_groups_sync.config
|
||||
parent: site_tools.admin_config
|
||||
weight: 6
|
||||
@@ -0,0 +1,11 @@
|
||||
ldap_research_groups_sync.tab.config:
|
||||
title: 'Configuration'
|
||||
route_name: ldap_research_groups_sync.config
|
||||
base_route: ldap_research_groups_sync.config
|
||||
weight: 0
|
||||
|
||||
ldap_research_groups_sync.tab.access_rules:
|
||||
title: 'Access Rules'
|
||||
route_name: ldap_research_groups_sync.access_rules
|
||||
base_route: ldap_research_groups_sync.config
|
||||
weight: 10
|
||||
238
ldap_research_groups_sync/ldap_research_groups_sync.module
Normal file
238
ldap_research_groups_sync/ldap_research_groups_sync.module
Normal file
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Module to synchronize research groups from LDAP to groups.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\field\FieldConfigInterface;
|
||||
use Drupal\ldap_research_groups_sync\LdapResearchGroupsSync;
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function ldap_research_groups_sync_help($route_name, RouteMatchInterface $route_match) {
|
||||
switch ($route_name) {
|
||||
case 'help.page.ldap_research_groups_sync':
|
||||
return '<p>' . t('This module synchronizes research groups from an LDAP server to groups through cron.') . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_cron().
|
||||
*/
|
||||
function ldap_research_groups_sync_cron() {
|
||||
// Check if module is properly configured
|
||||
$config = \Drupal::config('ldap_research_groups_sync.settings');
|
||||
$ldap_server_id = $config->get('ldap_server_id');
|
||||
$ldap_query_id = $config->get('ldap_query_id');
|
||||
|
||||
// Validate LDAP server
|
||||
try {
|
||||
$entity_type_manager = \Drupal::entityTypeManager();
|
||||
$server_storage = $entity_type_manager->getStorage('ldap_server');
|
||||
$server = $server_storage->load($ldap_server_id);
|
||||
|
||||
if (!$server || !$server->get('status')) {
|
||||
\Drupal::logger('ldap_research_groups_sync')->warning('Synchronization cancelled: LDAP server "@server_id" not found or inactive. Configure at /admin/config/local-modules/ldap-research-groups-sync', [
|
||||
'@server_id' => $ldap_server_id,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
\Drupal::logger('ldap_research_groups_sync')->warning('Synchronization cancelled: error checking LDAP server: @message', [
|
||||
'@message' => $e->getMessage(),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate LDAP query
|
||||
try {
|
||||
if ($entity_type_manager->hasDefinition('ldap_query_entity')) {
|
||||
$query_storage = $entity_type_manager->getStorage('ldap_query_entity');
|
||||
$query = $query_storage->load($ldap_query_id);
|
||||
|
||||
if (!$query || !$query->get('status')) {
|
||||
\Drupal::logger('ldap_research_groups_sync')->warning('Synchronization cancelled: LDAP query "@query_id" not found or inactive. Configure at /admin/config/local-modules/ldap-research-groups-sync', [
|
||||
'@query_id' => $ldap_query_id,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
\Drupal::logger('ldap_research_groups_sync')->warning('Synchronization cancelled: ldap_query module not available.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
\Drupal::logger('ldap_research_groups_sync')->warning('Synchronization cancelled: error checking LDAP query: @message', [
|
||||
'@message' => $e->getMessage(),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate group type
|
||||
try {
|
||||
$group_type_id = $config->get('group_type_id');
|
||||
$group_type_storage = $entity_type_manager->getStorage('group_type');
|
||||
$group_type = $group_type_storage->load($group_type_id);
|
||||
|
||||
if (!$group_type) {
|
||||
\Drupal::logger('ldap_research_groups_sync')->warning('Synchronization cancelled: group type "@type_id" not found. Configure at /admin/config/local-modules/ldap-research-groups-sync', [
|
||||
'@type_id' => $group_type_id,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
\Drupal::logger('ldap_research_groups_sync')->warning('Synchronization cancelled: error checking group type: @message', [
|
||||
'@message' => $e->getMessage(),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get LDAP synchronization service
|
||||
$ldap_sync = \Drupal::service('ldap_research_groups_sync.sync');
|
||||
|
||||
// Execute research groups synchronization
|
||||
try {
|
||||
$ldap_sync->syncResearchGroups();
|
||||
\Drupal::logger('ldap_research_groups_sync')->info('Research groups synchronization executed successfully.');
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
\Drupal::logger('ldap_research_groups_sync')->error('Error in research groups synchronization: @message', [
|
||||
'@message' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_access().
|
||||
*
|
||||
* Evaluates access rules configured in the module settings for view, update
|
||||
* and delete operations on existing entities.
|
||||
*/
|
||||
function ldap_research_groups_sync_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
// Skip group-related entities to avoid conflicts with the group module.
|
||||
$skip_types = ['group', 'group_content', 'group_relationship', 'group_role', 'group_type'];
|
||||
if (in_array($entity->getEntityTypeId(), $skip_types, TRUE)) {
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
return \Drupal::service('ldap_research_groups_sync.access_rules')
|
||||
->checkAccess($entity, $operation, $account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_create_access().
|
||||
*
|
||||
* Evaluates access rules configured in the module settings for create
|
||||
* operations on new entities.
|
||||
*/
|
||||
function ldap_research_groups_sync_entity_create_access(AccountInterface $account, array $context, $entity_bundle) {
|
||||
$entity_type_id = $context['entity_type_id'] ?? '';
|
||||
|
||||
// Skip group-related entities.
|
||||
$skip_types = ['group', 'group_content', 'group_relationship', 'group_role', 'group_type'];
|
||||
if (in_array($entity_type_id, $skip_types, TRUE)) {
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
return \Drupal::service('ldap_research_groups_sync.access_rules')
|
||||
->checkCreateAccess($account, $entity_type_id, $entity_bundle ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_field_access().
|
||||
*
|
||||
* Denies edit access to fields managed by the LDAP sync in forms and APIs
|
||||
* (REST, JSON:API). Programmatic saves are not affected.
|
||||
*
|
||||
* Protected user fields:
|
||||
* - field_user_research_groups: multi-value reference to the research groups
|
||||
* the user belongs to, populated by our sync. Protecting this field
|
||||
* prevents the validation error "This entity cannot be referenced" that
|
||||
* occurs when the widget tries to validate the referenced group against
|
||||
* the current user's access.
|
||||
*/
|
||||
function ldap_research_groups_sync_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, ?FieldItemListInterface $items = NULL) {
|
||||
$protected_user_fields = [
|
||||
'field_user_research_groups',
|
||||
];
|
||||
|
||||
if (
|
||||
$field_definition->getTargetEntityTypeId() === 'user' &&
|
||||
in_array($field_definition->getName(), $protected_user_fields, TRUE) &&
|
||||
$operation === 'edit'
|
||||
) {
|
||||
// Sempre nega edição via UI/API, inclusive para o uid 1.
|
||||
// Saves programáticos (ldap_user, drush) não passam por este hook.
|
||||
return AccessResult::forbidden('This field is managed exclusively by LDAP synchronization.');
|
||||
}
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_user_presave().
|
||||
*
|
||||
* Protects fields managed by the LDAP sync from unauthorized programmatic
|
||||
* changes on existing users. Allows:
|
||||
* - Saves during authorized LDAP sync (LdapResearchGroupsSync::$syncing TRUE)
|
||||
* - New user creation (initial provisioning via ldap_user)
|
||||
* - Saves by users with the 'edit ldap managed user rg fields' permission
|
||||
*/
|
||||
function ldap_research_groups_sync_user_presave(\Drupal\user\UserInterface $user) {
|
||||
// Permite durante qualquer sync LDAP autorizado.
|
||||
if (LdapResearchGroupsSync::isSyncing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Permite na criação inicial do usuário (primeiro login LDAP).
|
||||
if ($user->isNew()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Permite se o usuário atual tem a permissão de bypass.
|
||||
if (\Drupal::currentUser()->hasPermission('edit ldap managed user rg fields')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$original = $user->original;
|
||||
if ($original === NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fields managed by LDAP that cannot be changed externally.
|
||||
$protected_fields = [
|
||||
'field_user_research_groups',
|
||||
];
|
||||
|
||||
foreach ($protected_fields as $field_name) {
|
||||
if (!$user->hasField($field_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$original_value = $original->get($field_name)->getValue();
|
||||
$new_value = $user->get($field_name)->getValue();
|
||||
|
||||
if ($original_value !== $new_value) {
|
||||
$user->set($field_name, $original_value);
|
||||
\Drupal::logger('ldap_research_groups_sync')->warning(
|
||||
'Unauthorized attempt to change @field on user @username was blocked. Use LDAP synchronization to update this field.',
|
||||
[
|
||||
'@field' => $field_name,
|
||||
'@username' => $user->getAccountName(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
administer ldap research groups sync:
|
||||
title: 'Administer LDAP Research Groups Sync'
|
||||
description: 'Configure the LDAP research groups synchronization.'
|
||||
restrict access: true
|
||||
|
||||
edit ldap managed user rg fields:
|
||||
title: 'Edit LDAP-managed research group fields on users'
|
||||
description: 'Allows manually editing fields such as field_user_research_groups that are normally managed by LDAP synchronization. Use only in emergencies.'
|
||||
restrict access: true
|
||||
@@ -0,0 +1,25 @@
|
||||
ldap_research_groups_sync.config:
|
||||
path: '/admin/config/local-modules/ldap-research-groups-sync'
|
||||
defaults:
|
||||
_form: '\Drupal\ldap_research_groups_sync\Form\LdapResearchGroupsSyncConfigForm'
|
||||
_title: 'LDAP Research Groups Sync'
|
||||
requirements:
|
||||
_permission: 'administer ldap research groups sync'
|
||||
|
||||
ldap_research_groups_sync.access_rules:
|
||||
path: '/admin/config/local-modules/ldap-research-groups-sync/access-rules'
|
||||
defaults:
|
||||
_form: '\Drupal\ldap_research_groups_sync\Form\AccessRulesForm'
|
||||
_title: 'Access Rules'
|
||||
requirements:
|
||||
_permission: 'administer ldap research groups sync'
|
||||
|
||||
ldap_research_groups_sync.access_rule_form:
|
||||
path: '/admin/config/local-modules/ldap-research-groups-sync/access-rule/{rule_index}'
|
||||
defaults:
|
||||
_form: '\Drupal\ldap_research_groups_sync\Form\AccessRuleForm'
|
||||
_title: 'Access Rule'
|
||||
rule_index: 'new'
|
||||
requirements:
|
||||
_permission: 'administer ldap research groups sync'
|
||||
rule_index: 'new|\d+'
|
||||
@@ -0,0 +1,8 @@
|
||||
services:
|
||||
ldap_research_groups_sync.sync:
|
||||
class: Drupal\ldap_research_groups_sync\LdapResearchGroupsSync
|
||||
arguments: ['@entity_type.manager', '@config.factory', '@logger.factory', '@ldap.bridge']
|
||||
|
||||
ldap_research_groups_sync.access_rules:
|
||||
class: Drupal\ldap_groups_sync\GroupAccessRulesService
|
||||
arguments: ['@config.factory', '@entity_type.manager', 'ldap_research_groups_sync.settings']
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Installs field_rg_department on the research_group group bundle.
|
||||
*
|
||||
* Usage (from Drupal root):
|
||||
* drush php-script modules/custom/ldap_research_groups_sync/scripts/install_field_rg_department.php
|
||||
*/
|
||||
|
||||
$module_path = \Drupal::service('extension.list.module')->getPath('ldap_research_groups_sync');
|
||||
$config_path = $module_path . '/config/optional';
|
||||
|
||||
$config_factory = \Drupal::configFactory();
|
||||
$yaml_parser = \Drupal::service('serialization.yaml');
|
||||
|
||||
$configs_to_install = [
|
||||
'field.storage.group.field_rg_department',
|
||||
'field.field.group.research_group.field_rg_department',
|
||||
'core.entity_form_display.group.research_group.default',
|
||||
'core.entity_view_display.group.research_group.default',
|
||||
];
|
||||
|
||||
$imported = 0;
|
||||
$skipped = 0;
|
||||
|
||||
foreach ($configs_to_install as $config_name) {
|
||||
$file = $config_path . '/' . $config_name . '.yml';
|
||||
|
||||
if (!file_exists($file)) {
|
||||
echo "ERROR: File not found: $file\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$existing = $config_factory->get($config_name);
|
||||
|
||||
// For display configs, always update (they already exist and need the new field).
|
||||
$is_display = str_starts_with($config_name, 'core.entity_');
|
||||
|
||||
if (!$existing->isNew() && !$is_display) {
|
||||
echo "SKIP: $config_name (already exists)\n";
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$data = $yaml_parser->decode(file_get_contents($file));
|
||||
$config_factory->getEditable($config_name)->setData($data)->save();
|
||||
|
||||
echo "OK: $config_name\n";
|
||||
$imported++;
|
||||
}
|
||||
|
||||
if ($imported > 0) {
|
||||
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
|
||||
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||
\Drupal::service('plugin.manager.field.widget')->clearCachedDefinitions();
|
||||
\Drupal::service('plugin.manager.field.formatter')->clearCachedDefinitions();
|
||||
\Drupal::service('config.factory')->clearStaticCache();
|
||||
|
||||
// Create the database table for the new field storage.
|
||||
$field_manager = \Drupal::service('entity_field.manager');
|
||||
$field_manager->clearCachedFieldDefinitions();
|
||||
$update_manager = \Drupal::entityDefinitionUpdateManager();
|
||||
$storage_defs = $field_manager->getFieldStorageDefinitions('group');
|
||||
if (isset($storage_defs['field_rg_department'])) {
|
||||
$update_manager->installFieldStorageDefinition(
|
||||
'field_rg_department',
|
||||
'group',
|
||||
'ldap_research_groups_sync',
|
||||
$storage_defs['field_rg_department']
|
||||
);
|
||||
echo "Schema update applied (group__field_rg_department table created).\n";
|
||||
}
|
||||
else {
|
||||
echo "WARNING: field_rg_department storage definition not found — table not created.\n";
|
||||
}
|
||||
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
|
||||
echo "\nDone. Imported: $imported, Skipped: $skipped\n";
|
||||
echo "Run 'drush cr' to clear all caches.\n";
|
||||
}
|
||||
else {
|
||||
echo "\nNothing imported. Skipped: $skipped\n";
|
||||
}
|
||||
40
ldap_research_groups_sync/src/Form/AccessRuleForm.php
Normal file
40
ldap_research_groups_sync/src/Form/AccessRuleForm.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ldap_research_groups_sync\Form;
|
||||
|
||||
use Drupal\ldap_groups_sync\Form\AccessRuleFormBase;
|
||||
|
||||
/**
|
||||
* Modal form for creating or editing a single access rule (Research Groups Sync).
|
||||
*/
|
||||
class AccessRuleForm extends AccessRuleFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigName(): string {
|
||||
return 'ldap_research_groups_sync.settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId(): string {
|
||||
return 'ldap_research_groups_sync_access_rule_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAccessRulesRoute(): string {
|
||||
return 'ldap_research_groups_sync.access_rules';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultGroupTypeId(): string {
|
||||
return 'research_group';
|
||||
}
|
||||
|
||||
}
|
||||
33
ldap_research_groups_sync/src/Form/AccessRulesForm.php
Normal file
33
ldap_research_groups_sync/src/Form/AccessRulesForm.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ldap_research_groups_sync\Form;
|
||||
|
||||
use Drupal\ldap_groups_sync\Form\AccessRulesFormBase;
|
||||
|
||||
/**
|
||||
* Lists and manages access rules for the LDAP Research Groups Sync module.
|
||||
*/
|
||||
class AccessRulesForm extends AccessRulesFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigName(): string {
|
||||
return 'ldap_research_groups_sync.settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId(): string {
|
||||
return 'ldap_research_groups_sync_access_rules_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAccessRuleFormRoute(): string {
|
||||
return 'ldap_research_groups_sync.access_rule_form';
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
1212
ldap_research_groups_sync/src/LdapResearchGroupsSync.php
Normal file
1212
ldap_research_groups_sync/src/LdapResearchGroupsSync.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ldap_research_groups_sync\Plugin\EntityReferenceSelection;
|
||||
|
||||
use Drupal\group\Plugin\EntityReferenceSelection\GroupSelection;
|
||||
|
||||
/**
|
||||
* Plugin for research group entity reference selection.
|
||||
*
|
||||
* Restricts selection to the 'research_group' group type.
|
||||
*
|
||||
* @EntityReferenceSelection(
|
||||
* id = "default:research_group",
|
||||
* label = @Translation("Research Group selection"),
|
||||
* entity_types = {"group"},
|
||||
* group = "default",
|
||||
* weight = 1
|
||||
* )
|
||||
*/
|
||||
class ResearchGroupSelection extends GroupSelection {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$query = parent::buildEntityQuery($match, $match_operator);
|
||||
$query->condition('type', 'research_group');
|
||||
return $query;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
# Portuguese (Brazil) translation for LDAP Research Groups Sync module
|
||||
# Copyright (c) 2026
|
||||
# This file is distributed under the same license as the LDAP Research Groups Sync module.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: LDAP Research Groups Sync 1.0.0\n"
|
||||
"POT-Creation-Date: 2026-02-27 00:00+0000\n"
|
||||
"PO-Revision-Date: 2026-02-27 00:00+0000\n"
|
||||
"Language-Team: Portuguese (Brazil)\n"
|
||||
"Language: pt-br\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: ldap_research_groups_sync.routing.yml
|
||||
msgid "LDAP Research Groups Sync"
|
||||
msgstr "Sincronização de Grupos de Pesquisa LDAP"
|
||||
|
||||
#: ldap_research_groups_sync.routing.yml
|
||||
msgid "Access Rules"
|
||||
msgstr "Regras de Acesso"
|
||||
|
||||
#: ldap_research_groups_sync.routing.yml
|
||||
msgid "Access Rule"
|
||||
msgstr "Regra de Acesso"
|
||||
|
||||
#: ldap_research_groups_sync.module
|
||||
msgid "This module synchronizes research groups from an LDAP server to groups through cron."
|
||||
msgstr "Este módulo sincroniza grupos de pesquisa de um servidor LDAP para grupos através do cron."
|
||||
|
||||
#: ldap_research_groups_sync.install
|
||||
msgid "Please ensure your group type has the required fields: field_rg_code, field_rg_phone, field_rg_mail, and field_rg_department (for department reference)."
|
||||
msgstr "Certifique-se de que o tipo de grupo possui os campos obrigatórios: field_rg_code, field_rg_phone, field_rg_mail e field_rg_department (para referência de departamento)."
|
||||
|
||||
msgid "LDAP Research Groups Sync module uninstalled."
|
||||
msgstr "Módulo LDAP Research Groups Sync desinstalado."
|
||||
|
||||
#: src/Form/LdapResearchGroupsSyncConfigForm.php
|
||||
|
||||
msgid "Group Type"
|
||||
msgstr "Tipo de Grupo"
|
||||
|
||||
msgid "Target Group Type"
|
||||
msgstr "Tipo de Grupo Alvo"
|
||||
|
||||
msgid "Select the group type where research groups will be synchronized. <br><strong>Required fields:</strong> field_rg_code, field_rg_phone, field_rg_mail"
|
||||
msgstr "Selecione o tipo de grupo onde os grupos de pesquisa serão sincronizados. <br><strong>Campos obrigatórios:</strong> field_rg_code, field_rg_phone, field_rg_mail"
|
||||
|
||||
msgid "- Select a group type -"
|
||||
msgstr "- Selecione um tipo de grupo -"
|
||||
|
||||
msgid "The default \"research_group\" group type is not installed."
|
||||
msgstr "O tipo de grupo padrão \"research_group\" não está instalado."
|
||||
|
||||
msgid "Install Default Configuration"
|
||||
msgstr "Instalar Configuração Padrão"
|
||||
|
||||
msgid "The button above will create:<ul>\n <li>Group type \"research_group\" with all required fields</li>\n <li>User fields for research group synchronization</li>\n <li>Default group roles and displays</li>\n </ul>Or you can <a href=\"@url\">create a custom group type</a> manually."
|
||||
msgstr "O botão acima irá criar:<ul>\n <li>Tipo de grupo \"research_group\" com todos os campos obrigatórios</li>\n <li>Campos de usuário para sincronização de grupo de pesquisa</li>\n <li>Papéis e exibições padrão do grupo</li>\n </ul>Ou você pode <a href=\"@url\">criar um tipo de grupo personalizado</a> manualmente."
|
||||
|
||||
msgid "Create New Group Type"
|
||||
msgstr "Criar Novo Tipo de Grupo"
|
||||
|
||||
msgid "Manage Group Type"
|
||||
msgstr "Gerenciar Tipo de Grupo"
|
||||
|
||||
msgid "Manage Fields"
|
||||
msgstr "Gerenciar Campos"
|
||||
|
||||
msgid "LDAP Server"
|
||||
msgstr "Servidor LDAP"
|
||||
|
||||
msgid "Select the LDAP server configured for research groups synchronization."
|
||||
msgstr "Selecione o servidor LDAP configurado para sincronização de grupos de pesquisa."
|
||||
|
||||
msgid "- Select a server -"
|
||||
msgstr "- Selecione um servidor -"
|
||||
|
||||
msgid "No LDAP server found. <a href=\"@url\">Configure an LDAP server</a> first."
|
||||
msgstr "Nenhum servidor LDAP encontrado. <a href=\"@url\">Configure um servidor LDAP</a> primeiro."
|
||||
|
||||
msgid "LDAP Query"
|
||||
msgstr "Consulta LDAP"
|
||||
|
||||
msgid "Select the LDAP query that will be used to search for research groups."
|
||||
msgstr "Selecione a consulta LDAP que será usada para buscar grupos de pesquisa."
|
||||
|
||||
msgid "- Select a query -"
|
||||
msgstr "- Selecione uma query -"
|
||||
|
||||
msgid "No LDAP query found for the selected server. <a href=\"@url\">Create a new LDAP query</a>."
|
||||
msgstr "Nenhuma query LDAP encontrada para o servidor selecionado. <a href=\"@url\">Crie uma nova query LDAP</a>."
|
||||
|
||||
msgid "Create New LDAP Query"
|
||||
msgstr "Criar Nova Query LDAP"
|
||||
|
||||
msgid "Edit Selected Query"
|
||||
msgstr "Editar Query Selecionada"
|
||||
|
||||
msgid "Attribute Mapping"
|
||||
msgstr "Mapeamento de Atributos"
|
||||
|
||||
msgid "Configure how LDAP attributes are mapped to target entity fields.<br><strong>Note:</strong> For \"User Reference\" mappings, the search attribute will be automatically obtained from the \"Account name attribute\" field configured in the selected LDAP server."
|
||||
msgstr "Configure como os atributos LDAP são mapeados para os campos da entidade alvo.<br><strong>Nota:</strong> Para mapeamentos do tipo \"Referência de Usuário\", o atributo de busca será obtido automaticamente do campo \"Atributo de nome de conta\" configurado no servidor LDAP selecionado."
|
||||
|
||||
msgid "Entity Field"
|
||||
msgstr "Campo da Entidade"
|
||||
|
||||
msgid "LDAP Attribute"
|
||||
msgstr "Atributo LDAP"
|
||||
|
||||
msgid "Mapping Type"
|
||||
msgstr "Tipo de Mapeamento"
|
||||
|
||||
msgid "Remove"
|
||||
msgstr "Remover"
|
||||
|
||||
msgid "No mappings configured."
|
||||
msgstr "Nenhum mapeamento configurado."
|
||||
|
||||
msgid "- Select a field -"
|
||||
msgstr "- Selecione um campo -"
|
||||
|
||||
msgid "- Select an attribute -"
|
||||
msgstr "- Selecione um atributo -"
|
||||
|
||||
msgid "Simple (text)"
|
||||
msgstr "Simples (texto)"
|
||||
|
||||
msgid "User Reference (DN → User)"
|
||||
msgstr "Referência de Usuário (DN → Usuário)"
|
||||
|
||||
msgid "Department Reference (code → Department)"
|
||||
msgstr "Referência de Departamento (código → Departamento)"
|
||||
|
||||
msgid "Add Mapping"
|
||||
msgstr "Adicionar Mapeamento"
|
||||
|
||||
msgid "Remove Selected"
|
||||
msgstr "Remover Selecionados"
|
||||
|
||||
msgid "Member Synchronization"
|
||||
msgstr "Sincronização de Membros"
|
||||
|
||||
msgid "Enable member synchronization from LDAP attribute"
|
||||
msgstr "Habilitar sincronização de membros a partir do atributo LDAP"
|
||||
|
||||
msgid "When enabled, group memberships are managed based on the LDAP member attribute of each group entry. Members are added or removed to match the LDAP list."
|
||||
msgstr "Quando habilitado, as associações de membros do grupo são gerenciadas com base no atributo de membros LDAP de cada entrada de grupo. Membros são adicionados ou removidos para corresponder à lista LDAP."
|
||||
|
||||
msgid "Member LDAP attribute"
|
||||
msgstr "Atributo LDAP de membros"
|
||||
|
||||
msgid "Name of the LDAP attribute on each group entry that lists its members (as DNs or UIDs). Common values: <code>member</code>, <code>uniqueMember</code>, <code>memberUid</code>. The attribute must be included in the LDAP query."
|
||||
msgstr "Nome do atributo LDAP em cada entrada de grupo que lista seus membros (como DNs ou UIDs). Valores comuns: <code>member</code>, <code>uniqueMember</code>, <code>memberUid</code>. O atributo deve estar incluído na query LDAP."
|
||||
|
||||
msgid "Group Role Mapping"
|
||||
msgstr "Mapeamento de Papéis do Grupo"
|
||||
|
||||
msgid "Configure how user attributes map to group roles. Each role can have its own mapping criteria."
|
||||
msgstr "Configure como os atributos do usuário são mapeados para papéis do grupo. Cada papel pode ter seus próprios critérios de mapeamento."
|
||||
|
||||
msgid "Enable role mapping"
|
||||
msgstr "Habilitar mapeamento de papéis"
|
||||
|
||||
msgid "When enabled, users will be assigned group roles based on the mappings below."
|
||||
msgstr "Quando habilitado, os usuários receberão papéis de grupo com base nos mapeamentos abaixo."
|
||||
|
||||
msgid "Group Role"
|
||||
msgstr "Papel do Grupo"
|
||||
|
||||
msgid "Source"
|
||||
msgstr "Fonte"
|
||||
|
||||
msgid "User Field / LDAP Attribute"
|
||||
msgstr "Campo do Usuário / Atributo LDAP"
|
||||
|
||||
msgid "Group Field / Values"
|
||||
msgstr "Campo do Grupo / Valores"
|
||||
|
||||
msgid "No role mappings configured. Users will be assigned the default role."
|
||||
msgstr "Nenhum mapeamento de papel configurado. Os usuários receberão o papel padrão."
|
||||
|
||||
msgid "- Select a role -"
|
||||
msgstr "- Selecione um papel -"
|
||||
|
||||
msgid "User Field"
|
||||
msgstr "Campo do Usuário"
|
||||
|
||||
msgid "LDAP Attribute"
|
||||
msgstr "Atributo LDAP"
|
||||
|
||||
msgid "Group Field Match"
|
||||
msgstr "Correspondência de Campo do Grupo"
|
||||
|
||||
msgid "- Select user field -"
|
||||
msgstr "- Selecione campo do usuário -"
|
||||
|
||||
msgid "- Select attribute/field -"
|
||||
msgstr "- Selecione atributo/campo -"
|
||||
|
||||
msgid "- Select group field -"
|
||||
msgstr "- Selecione campo do grupo -"
|
||||
|
||||
msgid "e.g., Director, Manager"
|
||||
msgstr "ex: Diretor, Gerente"
|
||||
|
||||
msgid "Add Role Mapping"
|
||||
msgstr "Adicionar Mapeamento de Papel"
|
||||
|
||||
msgid "Save Configuration"
|
||||
msgstr "Salvar Configuração"
|
||||
|
||||
msgid "Test Connection"
|
||||
msgstr "Testar Conexão"
|
||||
|
||||
msgid "Synchronize Research Groups"
|
||||
msgstr "Sincronizar Grupos de Pesquisa"
|
||||
|
||||
msgid "Error loading LDAP servers: @message"
|
||||
msgstr "Erro ao carregar servidores LDAP: @message"
|
||||
|
||||
msgid "Error loading query attributes: @message"
|
||||
msgstr "Erro ao carregar atributos da query: @message"
|
||||
|
||||
msgid "LDAP attribute is required when field is selected."
|
||||
msgstr "O atributo LDAP é obrigatório quando um campo é selecionado."
|
||||
|
||||
msgid "Vocabulary field is required when attribute is selected."
|
||||
msgstr "O campo vocabulário é obrigatório quando um atributo é selecionado."
|
||||
|
||||
msgid "Configuration saved successfully."
|
||||
msgstr "Configuração salva com sucesso."
|
||||
|
||||
msgid "Please select an LDAP server to test."
|
||||
msgstr "Por favor, selecione um servidor LDAP para testar."
|
||||
|
||||
msgid "LDAP server \"@server\" is configured and active."
|
||||
msgstr "Servidor LDAP \"@server\" está configurado e ativo."
|
||||
|
||||
msgid "LDAP server not found or inactive."
|
||||
msgstr "Servidor LDAP não encontrado ou inativo."
|
||||
|
||||
msgid "Error testing connection: @message"
|
||||
msgstr "Erro ao testar conexão: @message"
|
||||
|
||||
msgid "Please fix the errors in the form before running the synchronization."
|
||||
msgstr "Corrija os erros no formulário antes de executar a sincronização."
|
||||
|
||||
msgid "Synchronization completed successfully. Check the logs for details."
|
||||
msgstr "Sincronização executada com sucesso. Verifique os logs para detalhes."
|
||||
|
||||
msgid "Error during synchronization: @message"
|
||||
msgstr "Erro durante a sincronização: @message"
|
||||
|
||||
msgid "Internal"
|
||||
msgstr "Interno"
|
||||
|
||||
msgid "Outsider"
|
||||
msgstr "Externo"
|
||||
|
||||
msgid "Error loading group roles: @message"
|
||||
msgstr "Erro ao carregar papéis do grupo: @message"
|
||||
|
||||
msgid "Error loading user fields: @message"
|
||||
msgstr "Erro ao carregar campos do usuário: @message"
|
||||
|
||||
msgid "The ldap_query module is not available. LDAP queries cannot be loaded."
|
||||
msgstr "O módulo ldap_query não está disponível. As queries LDAP não podem ser carregadas."
|
||||
|
||||
msgid "Error loading LDAP queries: @message"
|
||||
msgstr "Erro ao carregar queries LDAP: @message"
|
||||
|
||||
msgid "Label (group title)"
|
||||
msgstr "Rótulo (título do grupo)"
|
||||
|
||||
msgid "Group type \"@type\" not found. Please create it first or select a different group type."
|
||||
msgstr "Tipo de grupo \"@type\" não encontrado. Crie-o primeiro ou selecione um tipo de grupo diferente."
|
||||
|
||||
msgid "Error loading group types: @message"
|
||||
msgstr "Erro ao carregar tipos de grupo: @message"
|
||||
|
||||
msgid "Configuration directory not found: @path"
|
||||
msgstr "Diretório de configuração não encontrado: @path"
|
||||
|
||||
msgid "Configuration @name already exists, skipping."
|
||||
msgstr "Configuração @name já existe, pulando."
|
||||
|
||||
msgid "Successfully imported @count configuration files."
|
||||
msgstr "Importados com sucesso @count arquivos de configuração."
|
||||
|
||||
msgid "No new configuration files were imported. All configurations already exist."
|
||||
msgstr "Nenhum arquivo de configuração novo foi importado. Todas as configurações já existem."
|
||||
|
||||
msgid "Error importing configuration: @message"
|
||||
msgstr "Erro ao importar configuração: @message"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user