View source
<?php
namespace Drupal\data_policy;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Link;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\data_policy\Entity\DataPolicyInterface;
use Drupal\data_policy\Entity\UserConsentInterface;
class DataPolicyConsentManager implements DataPolicyConsentManagerInterface {
use StringTranslationTrait;
protected $configFactory;
protected $currentUser;
protected $entityTypeManager;
protected $entity;
protected $database;
protected $entityRepository;
public function __construct(ConfigFactoryInterface $config_factory, AccountProxyInterface $current_user, EntityTypeManagerInterface $entity_type_manager, Connection $database, EntityRepositoryInterface $entity_repository) {
$this->configFactory = $config_factory;
$this->currentUser = $current_user;
$this->entityTypeManager = $entity_type_manager;
$this->database = $database;
$this->entityRepository = $entity_repository;
}
public function needConsent() {
return $this
->isDataPolicy() && !$this->currentUser
->hasPermission('without consent');
}
public function addCheckbox(array &$form) {
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
$entity_ids = $this
->getEntityIdsFromConsentText();
$revisions = $this
->getRevisionsByEntityIds($entity_ids);
$links = [];
$query = $this->database
->select('user_consent', 'uc');
$query
->condition('status', TRUE);
$query
->condition('state', UserConsentInterface::STATE_AGREE);
$query
->condition('user_id', $this->currentUser
->id());
$query
->join('user_consent__data_policy_revision_id', 'ucr', 'uc.id = ucr.entity_id');
$query
->addField('ucr', 'data_policy_revision_id_value');
$user_agree_revision_ids = $query
->execute()
->fetchCol();
foreach ($revisions as $key => $revision) {
$revision = $this->entityRepository
->getTranslationFromContext($revision);
$links[$key] = Link::createFromRoute(strtolower($revision
->getName()), 'data_policy.data_policy', [
'id' => $revision
->id(),
], [
'attributes' => [
'class' => [
'use-ajax',
],
'data-dialog-type' => 'modal',
'data-dialog-options' => Json::encode([
'title' => $revision
->getName(),
'width' => 700,
'height' => 700,
]),
'checked' => in_array($revision
->getRevisionId(), $user_agree_revision_ids),
],
]);
}
$enforce_consent_text = $this
->getConfig('consent_text');
$items = preg_split('/\\R/', $enforce_consent_text);
$form['account']['data_policy'] = [
'#type' => 'details',
'#tree' => TRUE,
'#weight' => 110,
'#open' => TRUE,
];
foreach ($links as $entity_id => $link) {
$data = [];
foreach ($items as $item) {
if (strpos($item, "[id:{$entity_id}") !== FALSE) {
$data = [
'text' => $item,
'required' => strpos($item, "[id:{$entity_id}*]") ? TRUE : FALSE,
];
}
continue;
}
$enforce_consent_text = str_replace([
"[id:{$entity_id}*]",
"[id:{$entity_id}]",
], $link
->toString(), $data['text']);
$form['account']['data_policy']['data_policy_' . $entity_id] = [
'#type' => 'checkbox',
'#title' => $enforce_consent_text,
'#required' => $data['required'],
'#weight' => 110 + $entity_id,
'#default_value' => $link
->getUrl()
->getOption('attributes')['checked'],
];
}
}
public function saveConsent($user_id, $action = NULL, $values = [
'state' => UserConsentInterface::STATE_UNDECIDED,
]) {
$user_consents = $this->entityTypeManager
->getStorage('user_consent')
->loadByProperties([
'user_id' => $user_id,
'status' => TRUE,
]);
$data_policy_storage = $this->entityTypeManager
->getStorage('data_policy');
$existing_states = array_map(function (UserConsentInterface $user_consent) {
return $user_consent->state->value;
}, $user_consents);
if ($action === 'submit') {
$first = FALSE;
foreach ($values as $value) {
$state = $this
->getStateNumber($value['state']);
$is_equals = TRUE;
foreach ($existing_states as $existing_state) {
if ($existing_state != $state) {
$is_equals = FALSE;
break;
}
}
if (empty($existing_states)) {
$is_equals = FALSE;
}
if ($is_equals) {
return;
}
if (!empty($user_consents) && $first === FALSE) {
foreach ($user_consents as $user_consent) {
$user_consent
->setPublished(FALSE)
->save();
$first = TRUE;
}
}
$data_policy = $data_policy_storage
->load($value['entity_id']);
$is_required = $this
->isRequiredEntity($value['entity_id']);
$this
->createUserConsent($data_policy, $user_id, $state, $is_required);
}
}
elseif ($action === 'visit') {
$state = $this
->getStateNumber($values['state']);
$entities = $this
->getEntityIdsFromConsentText();
if (!empty($existing_states)) {
$existing_revisions = array_map(function (UserConsentInterface $user_consent) {
return $user_consent->data_policy_revision_id->value;
}, $user_consents);
$revisions = $this
->getRevisionsByEntityIds($entities);
$revision_ids_from_consent_text = array_map(function (DataPolicyInterface $revision) {
return $revision
->getRevisionId();
}, $revisions);
$diff = array_diff($existing_revisions, $revision_ids_from_consent_text);
$confirmed = array_flip(array_intersect($existing_revisions, $revision_ids_from_consent_text));
if (!empty($diff)) {
foreach ($user_consents as $id => $user_consent) {
if (in_array($id, $confirmed)) {
continue;
}
$user_consent
->setPublished(FALSE)
->save();
}
foreach (array_diff($revision_ids_from_consent_text, array_flip($confirmed)) as $revision_id) {
$data_policy = $data_policy_storage
->loadRevision($revision_id);
$is_required = $this
->isRequiredEntity($data_policy
->id());
$this
->createUserConsent($data_policy, $user_id, $state, $is_required);
}
}
$is_equals = TRUE;
$skip = TRUE;
foreach ($existing_states as $existing_state) {
if ((int) $existing_state < (int) $state) {
$skip = FALSE;
break;
}
if ($existing_state != $state) {
$is_equals = FALSE;
break;
}
}
if ($is_equals || $skip) {
return;
}
}
foreach ($entities as $entity) {
$data_policy = $data_policy_storage
->load($entity);
$is_required = $this
->isRequiredEntity($entity);
$this
->createUserConsent($data_policy, $user_id, $state, $is_required);
}
}
}
private function getStateNumber($state) {
if ($state === TRUE) {
$state = UserConsentInterface::STATE_AGREE;
}
elseif ($state === FALSE) {
$state = UserConsentInterface::STATE_NOT_AGREE;
}
return $state;
}
public function getExistingUserConsents($user_id) {
return $this->entityTypeManager
->getStorage('user_consent')
->getQuery()
->condition('status', 1)
->condition('user_id', $user_id)
->execute();
}
private function createUserConsent(DataPolicyInterface $data_policy, $user_id, $state, $required) {
$this->entityTypeManager
->getStorage('user_consent')
->create()
->setRevision($data_policy)
->setOwnerId($user_id)
->set('state', $state)
->set('required', $required)
->save();
}
public function isDataPolicy() {
return !empty($this
->getEntityIdsFromConsentText());
}
public function getEntityIdsFromConsentText() : array {
$consent_text = $this
->getConfig('consent_text');
preg_match_all("#\\[id:(.*)\\]#", $consent_text, $matches);
foreach ($matches[1] as $match) {
$ids[] = (int) $match;
}
return $ids ?? [];
}
public function isRequiredEntityInEntities(array $data_policy_ids) : bool {
$consent_text = $this
->getConfig('consent_text');
preg_match_all("#\\[id:(.*)\\]#", $consent_text, $matches);
foreach ($matches[1] as $match) {
if (strpos($match, '*') !== FALSE && in_array((int) $match, $data_policy_ids)) {
return TRUE;
}
}
return FALSE;
}
public function isRequiredEntity($data_policy_id) : bool {
return $this
->isRequiredEntityInEntities([
$data_policy_id,
]);
}
public function getRevisionsByEntityIds(array $entity_ids) : array {
return $this->entityTypeManager
->getStorage('data_policy')
->loadMultiple($entity_ids);
}
public function getConfig($name) {
return $this->configFactory
->get('data_policy.data_policy')
->get($name);
}
}