Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions config/schema/decoupled_auth.schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,23 @@ decoupled_auth.settings:
label: 'Selected roles'
sequence:
type: string

entity_reference_selection.decoupled_auth_user:
type: entity_reference_selection
mapping:
filter:
type: mapping
label: 'Filter settings'
mapping:
type:
type: string
label: 'Filter by'
role:
type: sequence
label: 'Restrict to the selected roles'
sequence:
type: string
label: 'Role'
include_decoupled:
type: boolean
label: 'Include the decoupled users.'
1 change: 1 addition & 0 deletions modules/crm/decoupled_auth_crm.info.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ core: 8.x

dependencies:
- decoupled_auth
- og
- user
- profile
- address
Expand Down
41 changes: 41 additions & 0 deletions modules/crm/decoupled_auth_crm.install
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

/**
* @file
* Install, update and uninstall functions for the decoupled user authentication
* module.
*/

/**
* Implements hook_install().
*/
function decoupled_auth_crm_install() {
// Make Users an OG Group
Drupal\og\Og::groupManager()->addGroup('user', 'user');

// Add reference field to users.
$settings = ['field_name' => 'crm_organisation'];
$field = Drupal\og\Og::createField('og_group_ref', 'user', 'user', $settings);

$field->setSetting('handler', 'decoupled_auth_user');
$handler_settings = [
'include_decoupled' => 1,
'filter' => [
'type' => 'role',
'role' => [
'crm_org' => 'crm_org',
]
]
];
$field->setSetting('handler_settings', $handler_settings);
$field->save();
}

/**
* Implements hook_uninstall().
*/
function decoupled_auth_crm_uninstall() {
// Remove og organisation field.
$field = Drupal\field\Entity\FieldConfig::load('user.user.crm_organisation');
$field->delete();
}
228 changes: 228 additions & 0 deletions src/Plugin/EntityReferenceSelection/DecoupledUserSelection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
<?php

/**
* @file
* Contains \Drupal\decoupled_auth\Plugin\EntityReferenceSelection\DecoupledUserSelection.
*/

namespace Drupal\decoupled_auth\Plugin\EntityReferenceSelection;

use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\user\RoleInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Provides specific access control for the user entity type.
*
* @EntityReferenceSelection(
* id = "decoupled_auth_user",
* label = @Translation("Decoupled user selection"),
* entity_types = {"user"},
* group = "decoupled_auth_user",
* weight = 10
* )
*/
class DecoupledUserSelection extends DefaultSelection {

/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;

/**
* The user storage.
*
* @var \Drupal\user\UserStorageInterface
*/
protected $userStorage;

/**
* Constructs a new UserSelection object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler service.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
* @param \Drupal\Core\Database\Connection $connection
* The database connection.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user, Connection $connection) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_manager, $module_handler, $current_user);

$this->connection = $connection;
$this->userStorage = $entity_manager->getStorage('user');
}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity.manager'),
$container->get('module_handler'),
$container->get('current_user'),
$container->get('database')
);
}

/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$selection_handler_settings = $this->configuration['handler_settings'];

// Merge in default values.
$selection_handler_settings += array(
'filter' => array(
'type' => '_none',
),
'include_anonymous' => TRUE,
'include_decoupled' => TRUE,
);

$form['include_decoupled'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Include the decoupled users.'),
'#default_value' => $selection_handler_settings['include_decoupled'],
);

// Add user specific filter options.
$form['filter']['type'] = array(
'#type' => 'select',
'#title' => $this->t('Filter by'),
'#options' => array(
'_none' => $this->t('- None -'),
'role' => $this->t('User role'),
),
'#ajax' => TRUE,
'#limit_validation_errors' => array(),
'#default_value' => $selection_handler_settings['filter']['type'],
);

$form['filter']['settings'] = array(
'#type' => 'container',
'#attributes' => array('class' => array('entity_reference-settings')),
'#process' => array(array('\Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem', 'formProcessMergeParent')),
);

if ($selection_handler_settings['filter']['type'] == 'role') {
// Merge in default values.
$selection_handler_settings['filter'] += array(
'role' => NULL,
);

$form['filter']['settings']['role'] = array(
'#type' => 'checkboxes',
'#title' => $this->t('Restrict to the selected roles'),
'#required' => TRUE,
'#options' => array_diff_key(user_role_names(TRUE), array(RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID)),
'#default_value' => $selection_handler_settings['filter']['role'],
);
}

$form += parent::buildConfigurationForm($form, $form_state);

return $form;
}

/**
* {@inheritdoc}
*/
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
$query = parent::buildEntityQuery($match, $match_operator);

// The user entity doesn't have a label column.
if (isset($match)) {
$or = $query->orConditionGroup();
$or->condition('name', $match, $match_operator);
$or->condition('mail', $match, $match_operator);
$query->condition($or);
}

// Filter by role.
$handler_settings = $this->configuration['handler_settings'];
if (!empty($handler_settings['filter']['role'])) {
$query->condition('roles', $handler_settings['filter']['role'], 'IN');
}

// Adding the permission check is sadly insufficient for users: core
// requires us to also know about the concept of 'blocked' and 'active'.
if (!$this->currentUser->hasPermission('administer users')) {
$query->condition('status', 1);
}
return $query;
}

/**
* {@inheritdoc}
*/
public function createNewEntity($entity_type_id, $bundle, $label, $uid) {
$user = parent::createNewEntity($entity_type_id, $bundle, $label, $uid);

// In order to create a referenceable user, it needs to be active.
if (!$this->currentUser->hasPermission('administer users')) {
/** @var \Drupal\user\UserInterface $user */
$user->activate();
}

return $user;
}

/**
* {@inheritdoc}
*/
public function validateReferenceableNewEntities(array $entities) {
$entities = parent::validateReferenceableNewEntities($entities);
// Mirror the conditions checked in buildEntityQuery().
if (!empty($this->configuration['handler_settings']['filter']['role'])) {
$entities = array_filter($entities, function ($user) {
/** @var \Drupal\user\UserInterface $user */
return !empty(array_intersect($user->getRoles(), $this->configuration['handler_settings']['filter']['role']));
});
}
if (!$this->currentUser->hasPermission('administer users')) {
$entities = array_filter($entities, function ($user) {
/** @var \Drupal\user\UserInterface $user */
return $user->isActive();
});
}
return $entities;
}

/**
* {@inheritdoc}
*/
public function entityQueryAlter(SelectInterface $query) {
// Only show decoupled users if requested and user has permission.
$handler_settings = $this->configuration['handler_settings'];
if (isset($handler_settings['include_decoupled']) && $handler_settings['include_decoupled']) {
// @TODO Use a better permission that administer users when available.
if (!$this->currentUser->hasPermission('administer users')) {
$query->isNotNull('name');
}
}
else {
$query->isNotNull('name');
}
}

}
Loading