Commit 4594ce7a authored by RoSk0's avatar RoSk0

Issue #2874755 by RoSk0, edurenye: Port user sync module.

parents bb77121b 87c14bf3
rules: {}
auto_sync_user_create: FALSE
contact_load: FALSE
contact_show: FALSE
# Schema for the configuration files of the CRM Core User Synchronization module.
crm_core_user_sync.settings:
type: config_object
label: 'CRM Core User Synchronization settings'
mapping:
rules:
type: sequence
label: 'Rules'
sequence:
type: crm_core_user_sync.rule
auto_sync_user_create:
type: boolean
label: 'Auto sync user create'
contact_load:
type: boolean
label: 'Load contact related to the current user'
contact_show:
type: boolean
label: 'Show related contact information on the user profile'
crm_core_user_sync.rule:
type: mapping
label: 'Rule'
mapping:
role:
type: string
label: 'Role'
contact_type:
type: string
label: 'Contact type'
enabled:
type: boolean
label: 'Enabled'
weight:
type: integer
label: 'Weight'
name: CRM Core User Synchronization
type: module
description: 'Synchronizes crm contacts with users.'
description: 'Synchronizes CRM contacts with users.'
package: CRM Core
core: 8.x
......@@ -8,4 +8,3 @@ configure: crm_core_user_sync.sync
dependencies:
- crm_core:crm_core_contact
- relation:relation
<?php
use Drupal\relation\Entity\RelationType;
/**
* Implements hook_install()
*/
function crm_core_user_sync_install() {
$t = get_t();
// Add relation type
$relation_type_info = array(
'relation_type' => 'crm_core_user_sync',
'label' => $t('Contact'),
'reverse_label' => $t('User'),
'source_bundles' => array('user:user'),
'target_bundles' => array('crm_core_contact:*'),
'r_unique' => TRUE,
'directional' => TRUE,
);
RelationType::create($relation_type_info)->save();
}
/**
* Implements hook_uninstall()
*/
function crm_core_user_sync_uninstall() {
relation_type_delete('crm_core_user_sync');
variable_del('crm_core_user_sync_rules');
variable_del('crm_core_user_sync_auto_sync_user_create');
}
/**
* Implements hook_enable().
*/
function crm_core_user_sync_enable() {
$menu_items = array(
array(
'link_path' => 'admin/config/crm-core/user-sync',
'link_title' => 'Administer User Synchronization',
'menu_name' => 'crm-core-admin-menu',
),
);
foreach ($menu_items as $item) {
menu_link_save($item);
}
}
/**
* Implements hook_disable().
*/
function crm_core_user_sync_disable() {
//Remove links from crm-core-menu and crm-core-admin-menu.
$conditions = array(
'crm-core-admin-menu' => array(
'admin/config/crm-core/user-sync'
),
);
crm_core_ui_remove_links($conditions);
}
crm_core_user_sync.rule.new:
route_name: crm_core_user_sync.rule.new
title: Add new synchronization rule
weight: 1
appears_on:
- crm_core_user_sync.config
crm_core_user_sync.config:
title: 'User Synchronization'
description: 'Manage CRM Core user synchronization settings.'
route_name: crm_core_user_sync.config
parent: crm_core.config
weight: 0
crm_core_user_sync.config:
title: Configuration
route_name: crm_core_user_sync.config
base_route: crm_core_user_sync.config
crm_core_user_sync.relations:
title: Relations
route_name: entity.crm_core_user_sync_relation.collection
base_route: crm_core_user_sync.config
weight: 3
administer crm-core-user-sync:
title: 'Administer User Synchronization'
description: 'Access to configuration pages for User Synchronization'
edit own contact information:
title: 'Edit own contact information'
description: 'Allows user to edit his/her own contact record from the user profile form'
crm_core_user_sync.config:
path: '/admin/config/crm-core/user-sync'
defaults:
_form: 'Drupal\crm_core_user_sync\Form\SettingsForm'
_title: 'User Synchronization'
requirements:
_permission: 'administer crm-core-user-sync'
crm_core_user_sync.rule.new:
path: '/admin/config/crm-core/user-sync/new'
defaults:
_title: 'Add a new rule'
_form: 'Drupal\crm_core_user_sync\Form\RuleForm'
requirements:
_permission: 'administer crm-core-user-sync'
crm_core_user_sync.rule.edit:
path: '/admin/config/crm-core/user-sync/{rule_key}/edit'
defaults:
_title: 'Edit rule'
_form: 'Drupal\crm_core_user_sync\Form\RuleForm'
requirements:
_permission: 'administer crm-core-user-sync'
rule_key: \d+
crm_core_user_sync.rule.delete:
path: '/admin/config/crm-core/user-sync/{rule_key}/delete'
defaults:
_title: 'Are you sure you want to delete this rule?'
_form: 'Drupal\crm_core_user_sync\Form\RuleDeleteConfirmForm'
requirements:
_permission: 'administer crm-core-user-sync'
rule_key: \d+
crm_core_user_sync.rule.enable:
path: '/admin/config/crm-core/user-sync/{rule_key}/enable'
defaults:
_title: 'Enable rule'
_controller: '\Drupal\crm_core_user_sync\Controller\RuleStatusController::enable'
requirements:
_permission: 'administer crm-core-user-sync'
crm_core_user_sync.rule.disable:
path: '/admin/config/crm-core/user-sync/{rule_key}/disable'
defaults:
_title: 'Disable rule'
_controller: '\Drupal\crm_core_user_sync\Controller\RuleStatusController::disable'
requirements:
_permission: 'administer crm-core-user-sync'
services:
crm_core_user_sync.relation:
class: Drupal\crm_core_user_sync\CrmCoreUserSyncRelation
arguments: ['@entity_type.manager', '@crm_core_user_sync.relation_rules', '@logger.channel.crm_core_user_sync']
crm_core_user_sync.relation_rules:
class: Drupal\crm_core_user_sync\CrmCoreUserSyncRelationRules
arguments: ['@config.factory', 'crm_core_user_sync.settings']
crm_core_user_sync.request.event_subscriber:
class: Drupal\crm_core_user_sync\EventSubscriber\RequestSubscriber
arguments: ['@current_user', '@config.factory', '@crm_core_user_sync.relation', '@entity_type.manager']
tags:
- { name: event_subscriber }
logger.channel.crm_core_user_sync:
parent: logger.channel_base
arguments: ['crm_core_user_sync']
<?php
namespace Drupal\crm_core_user_sync\Controller;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Returns responses for CRM Core User Synchronization routes.
*/
class RuleStatusController extends ControllerBase {
/**
* Current request.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* Constructs the controller object.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* Current request.
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* Config factory.
*/
public function __construct(Request $request, ConfigFactoryInterface $configFactory) {
$this->request = $request;
$this->configFactory = $configFactory;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('request_stack')->getCurrentRequest(),
$container->get('config.factory')
);
}
/**
* Enable rule.
*/
public function enable() {
$rule_key = $this->request->get('rule_key');
$rules = $this->configFactory->getEditable('crm_core_user_sync.settings')->get('rules');
$rules[$rule_key]['enabled'] = TRUE;
$this->configFactory->getEditable('crm_core_user_sync.settings')->set('rules', $rules)->save();
return $this->redirect('crm_core_user_sync.config');
}
/**
* Disable rule.
*/
public function disable() {
$rule_key = $this->request->get('rule_key');
$rules = $this->configFactory->getEditable('crm_core_user_sync.settings')->get('rules');
$rules[$rule_key]['enabled'] = FALSE;
$this->configFactory->getEditable('crm_core_user_sync.settings')->set('rules', $rules)->save();
return $this->redirect('crm_core_user_sync.config');
}
}
<?php
namespace Drupal\crm_core_user_sync;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\crm_core_contact\Entity\Individual;
use Drupal\crm_core_contact\IndividualInterface;
use Drupal\crm_core_user_sync\Entity\Relation;
use Drupal\user\UserInterface;
/**
* Relation service.
*
* @package Drupal\crm_core_user_sync
*/
class CrmCoreUserSyncRelation implements CrmCoreUserSyncRelationInterface {
/**
* Relation storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $storage;
/**
* Relation rules service.
*
* @var \Drupal\crm_core_user_sync\CrmCoreUserSyncRelationRules
*/
protected $rules;
/**
* Logger channel.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
/**
* Constructs a CrmCoreUserSyncRelation object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\crm_core_user_sync\CrmCoreUserSyncRelationRules $rules
* Relation rules service.
* @param \Drupal\Core\Logger\LoggerChannelInterface $logger
* Logger channel.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, CrmCoreUserSyncRelationRules $rules, LoggerChannelInterface $logger) {
$this->storage = $entity_type_manager->getStorage('crm_core_user_sync_relation');
$this->rules = $rules;
$this->logger = $logger;
}
/**
* {@inheritdoc}
*/
public function getUserIndividualId($user_id) {
$individual_id = NULL;
$rids = $this->storage->getQuery()
->condition('user_id', $user_id)
->range(0, 1)
->execute();
if (!empty($rids)) {
$relation_id = reset($rids);
/* @var $relation \Drupal\crm_core_user_sync\Entity\Relation */
$relation = $this->storage->load($relation_id);
$individual_id = $relation->getIndividualId();
}
return $individual_id;
}
/**
* {@inheritdoc}
*/
public function getIndividualUserId($individual_id) {
$user_id = NULL;
$rids = $this->storage->getQuery()
->condition('individual_id', $individual_id)
->range(0, 1)
->execute();
if (!empty($rids)) {
$relation_id = reset($rids);
/* @var $relation \Drupal\crm_core_user_sync\Entity\Relation */
$relation = $this->storage->load($relation_id);
$user_id = $relation->getIndividualId();
}
return $user_id;
}
/**
* {@inheritdoc}
*/
public function getUserRelationId($user_id) {
$rids = $this->storage->getQuery()
->condition('user_id', $user_id)
->range(0, 1)
->execute();
if (!empty($rids)) {
return reset($rids);
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function getIndividualRelationId($individual_id) {
$rids = $this->storage->getQuery()
->condition('individual_id', $individual_id)
->range(0, 1)
->execute();
if (!empty($rids)) {
return reset($rids);
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function relate(UserInterface $account, IndividualInterface $contact = NULL) {
// No contact and $account->crm_core_no_auto_sync => no sync.
if (empty($contact) && !empty($account->crm_core_no_auto_sync)) {
return NULL;
}
if (empty($contact)) {
// Account already have related contact.
if ($this->getUserIndividualId($account->id())) {
return NULL;
}
// Get corresponding contact type.
$contact_type = $this->rules->getContactType($account);
// No rules configured.
if (!$contact_type) {
return NULL;
}
// Create the contact.
$contact = Individual::create(['type' => $contact_type]);
$contact->setOwner($account);
// For now we just add the name.
$contact->name->given = $account->getAccountName();
$contact->save();
}
// Check if contact can be synchronized to a contact.
if (!$this->rules->valid($account, $contact)) {
return NULL;
}
// Check if crm_core_user_sync relation exists for any of endpoint.
if ($this->getUserIndividualId($account->id()) ||
$this->getIndividualUserId($contact->id())) {
return NULL;
}
$relation = Relation::create();
$relation->setUser($account);
$relation->setIndividual($contact);
$relation->save();
$this->logger->notice('User @user @uid has been synchronized to the contact @contact_id, relation @rid has been created.', [
'@user' => $account->getDisplayName(),
'@uid' => $account->id(),
'@contact_id' => $contact->id(),
'@rid' => $relation->id(),
]);
return $contact;
}
}
<?php
namespace Drupal\crm_core_user_sync;
use Drupal\crm_core_contact\IndividualInterface;
use Drupal\user\UserInterface;
/**
* CrmCoreUserSyncRelation service.
*/
interface CrmCoreUserSyncRelationInterface {
/**
* Retrieves the individual contact id for specified user.
*
* @return int|null
* Individual id, if relation exists.
*/
public function getUserIndividualId($user_id);
/**
* Retrieves the user id for specified individual contact.
*
* @return int|null
* User id, if relation exists.
*/
public function getIndividualUserId($individual_id);
/**
* Retrieves the relation for specified user.
*
* @return int|null
* Relation ID, if exists.
*/
public function getUserRelationId($user_id);
/**
* Retrieves the user id for specified individual contact.
*
* @return int|null
* Relation ID, if exists.
*/
public function getIndividualRelationId($individual_id);
/**
* Synchronizes user and contact.
*
* @param \Drupal\user\UserInterface $account
* Account to be synchronized. Programmatically created accounts can
* override default behavior by setting
* $account->crm_core_no_auto_sync = TRUE.
* @param \Drupal\crm_core_contact\IndividualInterface $contact
* Contact to be associated with $account.
*
* @return \Drupal\crm_core_contact\ContactInterface
* A contact object.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function relate(UserInterface $account, IndividualInterface $contact = NULL);
}
<?php
namespace Drupal\crm_core_user_sync;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\crm_core_contact\IndividualInterface;
use Drupal\user\UserInterface;
/**
* CrmCoreUserSyncRelation service.
*/
class CrmCoreUserSyncRelationRules {
/**
* The configuration factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
protected $rules;
/**
* Constructs a CrmCoreUserSyncRelationRules object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param string $configName
* Name of the configuration object that stores rules.
*/
public function __construct(ConfigFactoryInterface $config_factory, $configName) {
$this->configFactory = $config_factory;
$this->configName = $configName;
}
/**
* Retrieves the individual contact id for specified user.
*
* @return int|null
* Individual id, if relation exists.
*/
protected function getRules() {
if ($this->rules === NULL) {
$rules = $this
->configFactory
->get($this->configName)
->get('rules');
uasort($rules, [$this, 'weightCmp']);
$this->rules = $rules;
}
return $this->rules;
}
/**
* Rules weight comparison function.
*/
protected function weightCmp(array $a, array $b) {
if ($a['weight'] == $b['weight']) {
return 0;
}
return ($a['weight'] < $b['weight']) ? -1 : 1;
}
/**
* Checks if provided contact can be linked to this account.
*
* @param \Drupal\user\UserInterface $account
* User account to check.
* @param \Drupal\crm_core_contact\IndividualInterface $contact
* Contact record to check.
*
* @return bool
* TRUE if the contact is valid.
*/
public function valid(UserInterface $account, IndividualInterface $contact) {
return $contact->bundle() === $this->getContactType($account);
}
/**
* Get contact type resolved from configured synchronization rules.
*
* @param \Drupal\user\UserInterface $account
* User account to check.
*
* @return string|false
* Intividual contact type (bundle) to be user for this user account.
*/
public function getContactType(UserInterface $account) {
foreach ($this->getRules() as $rule) {
if ($rule['enabled'] && $account->hasRole($rule['role'])) {
return $rule['contact_type'];
}
}
return FALSE;
}
}
<?php
namespace Drupal\crm_core_user_sync\Entity;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\crm_core_contact\IndividualInterface;
use Drupal\crm_core_user_sync\RelationInterface;
use Drupal\user\UserInterface;
/**
* Defines the relation entity class.
*
* @ContentEntityType(
* id = "crm_core_user_sync_relation",
* label = @Translation("Relation"),
* label_collection = @Translation("Relations"),
* handlers = {
* "view_builder" = "Drupal\crm_core_user_sync\RelationViewBuilder",
* "list_builder" = "Drupal\crm_core_user_sync\RelationListBuilder",
* "views_data" = "Drupal\views\EntityViewsData",
* "form" = {
* "add" = "Drupal\crm_core_user_sync\Form\RelationForm",
* "edit" = "Drupal\crm_core_user_sync\Form\RelationForm",
* "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm"
* },
* "route_provider" = {
* "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
* }
* },
* base_table = "crm_core_user_sync_relation",
* data_table = "crm_core_user_sync_relation_field_data",
* admin_permission = "administer crm-core-user-sync",
* entity_keys = {
* "id" = "id",
* "uuid" = "uuid"
* },
* links = {
* "add-form" = "/admin/config/crm-core/user-sync/relation/add",
* "canonical" = "/admin/config/crm-core/user-sync/relation/{crm_core_user_sync_relation}",
* "edit-form" = "/admin/config/crm-core/user-sync/relation/{crm_core_user_sync_relation}/edit",