diff --git a/ldap_departments_sync/ldap_departments_sync.links.menu.yml b/ldap_departments_sync/ldap_departments_sync.links.menu.yml index 83f4e0c..456d3c8 100644 --- a/ldap_departments_sync/ldap_departments_sync.links.menu.yml +++ b/ldap_departments_sync/ldap_departments_sync.links.menu.yml @@ -1,6 +1 @@ -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 +# Menu entry removed: the parent module ldap_groups_sync provides the unified menu entry. diff --git a/ldap_departments_sync/ldap_departments_sync.links.task.yml b/ldap_departments_sync/ldap_departments_sync.links.task.yml index a8a4334..6759678 100644 --- a/ldap_departments_sync/ldap_departments_sync.links.task.yml +++ b/ldap_departments_sync/ldap_departments_sync.links.task.yml @@ -1,11 +1,5 @@ ldap_departments_sync.tab.config: - title: 'Configuration' + title: 'Departments Sync' 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 + base_route: ldap_groups_sync.config weight: 10 diff --git a/ldap_departments_sync/ldap_departments_sync.routing.yml b/ldap_departments_sync/ldap_departments_sync.routing.yml index f208140..c9fd149 100644 --- a/ldap_departments_sync/ldap_departments_sync.routing.yml +++ b/ldap_departments_sync/ldap_departments_sync.routing.yml @@ -5,21 +5,3 @@ ldap_departments_sync.config: _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+' diff --git a/ldap_groups_sync.links.menu.yml b/ldap_groups_sync.links.menu.yml new file mode 100644 index 0000000..9446640 --- /dev/null +++ b/ldap_groups_sync.links.menu.yml @@ -0,0 +1,6 @@ +ldap_groups_sync.config: + title: 'LDAP Groups Sync' + description: 'Configurar sincronização de grupos do LDAP' + route_name: ldap_groups_sync.config + parent: site_tools.admin_config + weight: 4 diff --git a/ldap_groups_sync.links.task.yml b/ldap_groups_sync.links.task.yml new file mode 100644 index 0000000..105762e --- /dev/null +++ b/ldap_groups_sync.links.task.yml @@ -0,0 +1,11 @@ +ldap_groups_sync.tab.overview: + title: 'Overview' + route_name: ldap_groups_sync.config + base_route: ldap_groups_sync.config + weight: 0 + +ldap_groups_sync.tab.access_rules: + title: 'Access Rules' + route_name: ldap_groups_sync.access_rules + base_route: ldap_groups_sync.config + weight: 100 diff --git a/ldap_groups_sync.permissions.yml b/ldap_groups_sync.permissions.yml new file mode 100644 index 0000000..9fc04e4 --- /dev/null +++ b/ldap_groups_sync.permissions.yml @@ -0,0 +1,4 @@ +administer ldap groups sync: + title: 'Administrar LDAP Groups Sync' + description: 'Acesso à página unificada de configuração e regras de acesso.' + restrict access: true diff --git a/ldap_groups_sync.routing.yml b/ldap_groups_sync.routing.yml new file mode 100644 index 0000000..ed5af7b --- /dev/null +++ b/ldap_groups_sync.routing.yml @@ -0,0 +1,26 @@ +ldap_groups_sync.config: + path: '/admin/config/local-modules/ldap-groups-sync' + defaults: + _controller: '\Drupal\ldap_groups_sync\Controller\LdapGroupsSyncController::overview' + _title: 'LDAP Groups Sync' + requirements: + _permission: 'administer ldap groups sync' + +ldap_groups_sync.access_rules: + path: '/admin/config/local-modules/ldap-groups-sync/access-rules' + defaults: + _form: '\Drupal\ldap_groups_sync\Form\UnifiedAccessRulesForm' + _title: 'Access Rules' + requirements: + _permission: 'administer ldap groups sync' + +ldap_groups_sync.access_rule_form: + path: '/admin/config/local-modules/ldap-groups-sync/access-rule/{group_type}/{rule_index}' + defaults: + _form: '\Drupal\ldap_groups_sync\Form\GlobalAccessRuleForm' + _title: 'Access Rule' + rule_index: 'new' + requirements: + _permission: 'administer ldap groups sync' + rule_index: 'new|\d+' + group_type: 'departments|research_groups' diff --git a/ldap_research_groups_sync/ldap_research_groups_sync.links.menu.yml b/ldap_research_groups_sync/ldap_research_groups_sync.links.menu.yml index 9687b76..456d3c8 100644 --- a/ldap_research_groups_sync/ldap_research_groups_sync.links.menu.yml +++ b/ldap_research_groups_sync/ldap_research_groups_sync.links.menu.yml @@ -1,6 +1 @@ -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 +# Menu entry removed: the parent module ldap_groups_sync provides the unified menu entry. diff --git a/ldap_research_groups_sync/ldap_research_groups_sync.links.task.yml b/ldap_research_groups_sync/ldap_research_groups_sync.links.task.yml index 9e9dbff..5b02820 100644 --- a/ldap_research_groups_sync/ldap_research_groups_sync.links.task.yml +++ b/ldap_research_groups_sync/ldap_research_groups_sync.links.task.yml @@ -1,11 +1,5 @@ ldap_research_groups_sync.tab.config: - title: 'Configuration' + title: 'Research Groups Sync' 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 + base_route: ldap_groups_sync.config + weight: 20 diff --git a/ldap_research_groups_sync/ldap_research_groups_sync.routing.yml b/ldap_research_groups_sync/ldap_research_groups_sync.routing.yml index a4be2e7..582bf29 100644 --- a/ldap_research_groups_sync/ldap_research_groups_sync.routing.yml +++ b/ldap_research_groups_sync/ldap_research_groups_sync.routing.yml @@ -5,21 +5,3 @@ ldap_research_groups_sync.config: _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+' diff --git a/src/Controller/LdapGroupsSyncController.php b/src/Controller/LdapGroupsSyncController.php new file mode 100644 index 0000000..7ec47c1 --- /dev/null +++ b/src/Controller/LdapGroupsSyncController.php @@ -0,0 +1,50 @@ + [ + 'label' => $this->t('LDAP Departments Sync'), + 'description' => $this->t('Synchronizes department groups from LDAP.'), + ], + 'ldap_research_groups_sync' => [ + 'label' => $this->t('LDAP Research Groups Sync'), + 'description' => $this->t('Synchronizes research group entities from LDAP.'), + ], + ]; + + $rows = []; + foreach ($submodules as $module => $info) { + $enabled = $this->moduleHandler()->moduleExists($module); + $rows[] = [ + (string) $info['label'], + (string) $info['description'], + $enabled + ? ['data' => ['#markup' => '✓ ' . $this->t('Enabled') . '']] + : ['data' => ['#markup' => '✗ ' . $this->t('Disabled') . '']], + ]; + } + + return [ + '#type' => 'table', + '#header' => [ + $this->t('Module'), + $this->t('Description'), + $this->t('Status'), + ], + '#rows' => $rows, + ]; + } + +} diff --git a/src/Form/GlobalAccessRuleForm.php b/src/Form/GlobalAccessRuleForm.php new file mode 100644 index 0000000..52806a7 --- /dev/null +++ b/src/Form/GlobalAccessRuleForm.php @@ -0,0 +1,155 @@ +moduleHandler = $module_handler; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('config.factory'), + $container->get('entity_type.manager'), + $container->get('entity_type.bundle.info'), + $container->get('entity_field.manager'), + $container->get('current_route_match'), + $container->get('module_handler') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId(): string { + return 'ldap_groups_sync_global_access_rule_form'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state, $group_type = 'departments', $rule_index = 'new'): array { + // Priority for group type: + // 1. User's current selection submitted via AJAX (getValue). + // 2. Previously stored value across AJAX rebuilds (get). + // 3. Route parameter (initial page load). + $selected = $form_state->getValue('group_type'); + if ($selected !== NULL) { + $this->groupType = $selected; + } + else { + $this->groupType = $form_state->get('group_type') ?? $group_type; + } + $form_state->set('group_type', $this->groupType); + + // Resolve rule index the same way the parent will, so we know whether + // this is a new rule before calling parent::buildForm(). + $is_new = ($form_state->get('rule_index') ?? $rule_index) === 'new'; + + $form = parent::buildForm($form, $form_state, $rule_index); + + // Build options from enabled submodules only. + $options = []; + if ($this->moduleHandler->moduleExists('ldap_departments_sync')) { + $options['departments'] = $this->t('Departments'); + } + if ($this->moduleHandler->moduleExists('ldap_research_groups_sync')) { + $options['research_groups'] = $this->t('Research Groups'); + } + + $form['group_type'] = [ + '#type' => 'select', + '#title' => $this->t('Group Type'), + '#options' => $options, + '#default_value' => $this->groupType, + '#required' => TRUE, + '#disabled' => !$is_new, + '#weight' => -100, + ]; + + // Only attach AJAX when the field is editable (new rules). + if ($is_new) { + $form['group_type']['#ajax'] = [ + 'callback' => '::updateDependentFields', + 'wrapper' => 'access-rule-form-wrapper', + 'effect' => 'fade', + ]; + } + + return $form; + } + + /** + * {@inheritdoc} + */ + protected function getConfigName(): string { + return match($this->groupType) { + 'research_groups' => 'ldap_research_groups_sync.settings', + default => 'ldap_departments_sync.settings', + }; + } + + /** + * {@inheritdoc} + */ + protected function getDefaultGroupTypeId(): string { + return match($this->groupType) { + 'research_groups' => 'research_group', + default => 'departments', + }; + } + + /** + * {@inheritdoc} + */ + protected function getAccessRulesRoute(): string { + return 'ldap_groups_sync.access_rules'; + } + +} diff --git a/src/Form/UnifiedAccessRulesForm.php b/src/Form/UnifiedAccessRulesForm.php new file mode 100644 index 0000000..6327575 --- /dev/null +++ b/src/Form/UnifiedAccessRulesForm.php @@ -0,0 +1,283 @@ + [ + 'config' => 'ldap_departments_sync.settings', + 'module' => 'ldap_departments_sync', + 'label' => 'Departments', + ], + 'research_groups' => [ + 'config' => 'ldap_research_groups_sync.settings', + 'module' => 'ldap_research_groups_sync', + 'label' => 'Research Groups', + ], + ]; + + /** + * @var \Drupal\Core\Config\ConfigFactoryInterface + */ + protected $configFactory; + + /** + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * @var \Drupal\Core\Extension\ModuleHandlerInterface + */ + protected $moduleHandler; + + /** + * Constructor. + */ + public function __construct( + ConfigFactoryInterface $config_factory, + EntityTypeManagerInterface $entity_type_manager, + ModuleHandlerInterface $module_handler + ) { + $this->configFactory = $config_factory; + $this->entityTypeManager = $entity_type_manager; + $this->moduleHandler = $module_handler; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('config.factory'), + $container->get('entity_type.manager'), + $container->get('module_handler') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId(): string { + return 'ldap_groups_sync_unified_access_rules_form'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state): array { + $form['#attached']['library'][] = 'core/drupal.dialog.ajax'; + + $form['description'] = [ + '#type' => 'markup', + '#markup' => '
' . $this->t(
+ 'Define rules that restrict or grant entity operations based on group membership.
'
+ . 'Restrictive: if a matching rule exists and the user does not satisfy it, access is denied.
'
+ . 'Additive: the rule only grants extra access; other users keep their default permissions.'
+ ) . '