diff --git a/civiremote.module b/civiremote.module index ee01247..4fe3371 100644 --- a/civiremote.module +++ b/civiremote.module @@ -4,9 +4,7 @@ use Drupal\civiremote; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; -use Drupal\Core\Url; use Drupal\user\UserInterface; -use Symfony\Component\HttpFoundation\RedirectResponse; /** * Implements hook_entity_insert(). @@ -22,19 +20,7 @@ function civiremote_entity_insert(EntityInterface $entity) { * Implements hook_user_login(). */ function civiremote_user_login(UserInterface $account) { - // Synchronise user roles with CiviRemote roles retrieved from CiviCRM. - try { - civiremote\User::synchroniseRoles($account); - } - catch (Exception $exception) { - user_logout(); - Drupal::messenger()->addError( - t('Could not complete login. Please try again later or contact the site administrator.') - ); - $url = Url::fromRoute('')->toString(); - $response = new RedirectResponse($url); - $response->send(); - } + civiremote\User::login($account); } /** diff --git a/config/install/civiremote.settings.yml b/config/install/civiremote.settings.yml index 80ff6b6..4061f95 100644 --- a/config/install/civiremote.settings.yml +++ b/config/install/civiremote.settings.yml @@ -1,3 +1,4 @@ cmrf_connector: civiremote acquire_civiremote_id: false match_blocked_users: false +match_on_login: false diff --git a/config/schema/civiremote.schema.yml b/config/schema/civiremote.schema.yml index 51bcccb..3d7128c 100644 --- a/config/schema/civiremote.schema.yml +++ b/config/schema/civiremote.schema.yml @@ -10,6 +10,15 @@ civiremote.settings: match_blocked_users: type: boolean label: 'Match blocked users' + match_on_login: + type: boolean + label: 'Acquire CiviRemote ID on login' + match_on_login_exclude_roles: + type: sequence + label: 'Roles to exclude when matching on login' + sequence: + type: string + label: 'Role' match_contact_mapping: type: sequence label: 'Parameter mapping' diff --git a/src/Form/CiviRemoteConfigForm.php b/src/Form/CiviRemoteConfigForm.php index fbe10bc..4fe72c5 100644 --- a/src/Form/CiviRemoteConfigForm.php +++ b/src/Form/CiviRemoteConfigForm.php @@ -16,27 +16,35 @@ namespace Drupal\CiviRemote\Form; use Drupal; +use Drupal\Component\Utility\Html; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Form\ConfigFormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Link; use Drupal\Core\Url; use Drupal\field\Entity\FieldConfig; +use Drupal\user\RoleInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\cmrf_core; +use Drupal\user\RoleStorageInterface; class CiviRemoteConfigForm extends ConfigFormBase { - /* @var cmrf_core\Core $cmrf_core */ + /** @var cmrf_core\Core $cmrf_core */ public $cmrf_core; + /** @var \Drupal\user\RoleStorageInterface $roleStorage */ + public $roleStorage; + /** * CiviRemoteConfigForm constructor. * * @param cmrf_core\Core $cmrf_core + * @param \Drupal\user\RoleStorageInterface $roleStorage */ - public function __construct(cmrf_core\Core $cmrf_core) { + public function __construct(cmrf_core\Core $cmrf_core, RoleStorageInterface $roleStorage) { $this->cmrf_core = $cmrf_core; + $this->roleStorage = $roleStorage; } /** @@ -46,10 +54,13 @@ public static function create(ContainerInterface $container) { /** * Inject dependencies. * @var cmrf_core\Core $cmrf + * @var \Drupal\user\RoleStorageInterface $roleStorage */ $cmrf = $container->get('cmrf_core.core'); + $roleStorage = $container->get('entity_type.manager')->getStorage('user_role'); return new static( - $cmrf + $cmrf, + $roleStorage ); } @@ -84,14 +95,19 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#required' => TRUE, ]; - $form['acquire_civiremote_id'] = [ + $form['match_contacts'] = [ + '#type' => 'fieldset', + '#title' => $this->t('CiviCRM Contact Matching'), + ]; + + $form['match_contacts']['acquire_civiremote_id'] = [ '#type' => 'checkbox', '#title' => $this->t('Acquire CiviRemote ID'), '#description' => $this->t('Whether to match a new user to a CiviCRM contact and store the CiviRemote ID returned by CiviCRM.'), '#default_value' => $config->get('acquire_civiremote_id'), ]; - $form['match_blocked_users'] = [ + $form['match_contacts']['match_blocked_users'] = [ '#type' => 'checkbox', '#title' => $this->t('Match blocked users'), '#description' => $this->t('Whether to match blocked users to a CiviCRM contact. If unchecked, only active users will be matched.'), @@ -101,6 +117,27 @@ public function buildForm(array $form, FormStateInterface $form_state) { ], ]; + $form['match_contacts']['match_on_login'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Acquire CiviRemote ID on login'), + '#description' => $this->t('Whether to match existing users without a CiviRemote ID when they log in.'), + '#default_value' => $config->get('match_on_login'), + '#states' => [ + 'visible' => [':input[name="acquire_civiremote_id"]' => ['checked' => TRUE]], + ], + ]; + + $form['match_contacts']['match_on_login_exclude_roles'] = [ + '#type' => 'checkboxes', + '#title' => $this->t('Roles to exclude when matching on login'), + '#description' => $this->t('Users with one of the selected roles will be escluded from acquiring a CiviCRM Contact ID during login.'), + '#options' => array_map(fn(RoleInterface $role) => Html::escape($role->label()), $this->roleStorage->loadMultiple()), + '#default_value' => $config->get('match_on_login_exclude_roles') ?? [], + '#states' => [ + 'visible' => [':input[name="match_on_login"]' => ['checked' => TRUE]], + ], + ]; + $form['match_contact_mapping'] = [ '#type' => 'fieldset', '#title' => $this->t('Parameter mapping'), @@ -209,6 +246,8 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $config->set('cmrf_connector', $form_state->getValue('cmrf_connector')); $config->set('acquire_civiremote_id', $form_state->getValue('acquire_civiremote_id')); $config->set('match_blocked_users', $form_state->getValue('match_blocked_users')); + $config->set('match_on_login', $form_state->getValue('match_on_login')); + $config->set('match_on_login_exclude_roles', $form_state->getValue('match_on_login_exclude_roles')); $config->set('match_contact_mapping', $form_state->getValue('match_contact_mapping_table')); $config->save(); parent::submitForm($form, $form_state); diff --git a/src/User.php b/src/User.php index f73d637..78aaebc 100644 --- a/src/User.php +++ b/src/User.php @@ -45,6 +45,39 @@ public static function create(UserInterface $user) { } } + /** + * Act on user login. + * + * @param \Drupal\user\UserInterface $user + */ + public static function login(UserInterface $user) { + try { + // Acquire CiviRemote ID on login if configured. + if (!$civiremote_id = $user->get('civiremote_id')->getValue()) { + $config = Drupal::config('civiremote.settings'); + if ( + $config->get('acquire_civiremote_id') + && $config->get('match_on_login') + && [] === array_intersect($user->getRoles(), $config->get('match_on_login_exclude_roles')) + ) { + self::matchContact($user); + } + } + + // Synchronise user roles with CiviRemote roles retrieved from CiviCRM. + self::synchroniseRoles($user); + } + catch (\Exception $exception) { + user_logout(); + Drupal::messenger()->addError( + t('Could not complete login. Please try again later or contact the site administrator.') + ); + $url = Url::fromRoute('')->toString(); + $response = new RedirectResponse($url); + $response->send(); + } + } + /** * Match a CiviCRM contact and set the returned CiviRemote ID on the user. *