grant-1.x-dev/src/GrantMain.php

src/GrantMain.php
<?php

namespace Drupal\grant;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Utility\Html;
use Drupal\Component\Uuid\Uuid;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Site\Settings;
use Drupal\grant\Entity\Grant;
use Drupal\multiple_email\EmailInterface;
use Drupal\user\UserInterface;

/**
 * Provide main class for grant module.
 */
final class GrantMain implements GrantMainInterface {

  /**
   * Constructs an GrantMain object.
   */
  public function __construct(
    private readonly AccountProxyInterface $account,
    private readonly CacheBackendInterface $cacheBackend,
    private readonly CurrentPathStack $pathCurrent,
    private readonly EntityRepositoryInterface $entityRepository,
    private readonly EntityTypeManagerInterface $entityTypeManager,
    private readonly ModuleHandlerInterface $moduleHandler,
    private readonly TimeInterface $time,
  ) {}

  /**
   * {@inheritdoc}
   */
  public function getGrantConfigs() {
    $grant_config = Settings::get('grant', []);
    if (!isset($grant_config['max_deph'])) {
      $grant_config['max_deph'] = 7;
    }
    if (!isset($grant_config['entities'])) {
      $grant_config['entities'] = [];
    }
    return $grant_config;
  }

  /**
   * {@inheritdoc}
   */
  public function entityLoadUuid($e_type = '', $e_uuid = '') {
    $return_default = NULL;
    $e_types_all = $this->entityTypeManager->getDefinitions();
    if (!in_array($e_type, array_keys($e_types_all))) {
      return $return_default;
    }
    $entity = $this->entityRepository->loadEntityByUuid($e_type, $e_uuid);

    if ($entity instanceof ContentEntityInterface) {
      return $entity;
    }
    return $return_default;
  }

  /**
   * {@inheritdoc}
   */
  public function addGrant($values = []) {
    $return = NULL;
    $grant_configs = $this->getGrantConfigs() ?? [];
    $e_type = $values['entity_type'];
    $e_uuid = $values['entity_uuid'];
    $entity = $this->entityLoadUuid($e_type, $e_uuid);
    if ($entity instanceof ContentEntityInterface) {
      $e_bundle = $entity->bundle();
      $config = $grant_configs['entities'][$e_type][$e_bundle] ?? [];

      $uid = $this->account->id();
      $current_user = $this->entityTypeManager->getStorage('user')->load($uid);
      $current_u3id = $current_user->uuid();

      $assign_mail = trim($values['email']) ?? '-';
      $e_values = [
        'status' => 0,
        'role' => $values['role'],
        'note' => trim($values['note']),
        'user' => $current_u3id,
        'email' => $assign_mail,
        'entity_type' => $e_type,
        'entity_uuid' => $e_uuid,
      ];

      $auto_assign = $config['assign_auto'] ?? FALSE;
      if ($auto_assign) {
        $assignee = user_load_by_mail($assign_mail);
        if ($assignee instanceof UserInterface) {
          $e_values['status'] = 1;
          $e_values['assignee'] = $assignee->uuid();
          $e_values['assigned'] = $this->time->getRequestTime();
        }
      }

      $grant = Grant::create($e_values);
      $grant->save();
      $return = $grant;
    }
    return $return;
  }

  /**
   * {@inheritdoc}
   */
  public function grantChangeCacheClear($grant_entity) {
    /** @var \Drupal\grant\GrantInterface $grant_entity */
    $assignee_uuid = $grant_entity->get("assignee")->getValue()[0]['target_uuid'] ?? 0;
    if ($assignee_uuid != 0) {
      $cache_id = 'grant_uag:' . $assignee_uuid;
      $this->cacheBackend->delete($cache_id);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function createGrantAccessCheckString($options = []) {
    if (isset($options['grant_role'])) {
      $check = 'role';
      $check_value = (string) implode('+', $options['grant_role']);
    }
    else {
      $check = 'perm';
      if (\is_array($options['grant_perm'])) {
        $check_value = (string) implode('+', $options['grant_perm']);
      }
      $check_value = (string) $options['grant_perm'];
    }
    $check_string = $check . ':' . $check_value . '|';

    $e_type_raw = $options['e_type'] ?? '';
    $e_type = trim($e_type_raw);
    if ($e_type != '') {
      $check_string .= "type_name:" . $e_type;
    }
    else {
      $e_type_arg = $options['e_type_arg'] ?? 1;
      $check_string .= "type:" . (string) $e_type_arg;
    }
    $check_string .= ',';
    if ($options['e_id_type'] == 'uuid') {
      $check_string .= 'uuid:';
    }
    else {
      $check_string .= 'id:';
    }
    $e_id_arg = $options['e_id_arg'] ?? 2;
    $check_string .= (string) $e_id_arg;
    return $check_string;
  }

  /**
   * {@inheritdoc}
   */
  public function userAssignedGrantHasAccessPathCurrent($options = [], $account = NULL) {
    $access = FALSE;
    $grant_configs = $this->getGrantConfigs() ?? [];
    $args_raw = explode('/', $this->pathCurrent->getPath());

    $e_type_raw = $options['e_type'] ?? '';
    $e_type = trim($e_type_raw);
    if ($e_type == '') {
      $e_type_arg = $options['e_type_arg'] ?? 1;
      if (isset($args_raw[$e_type_arg])) {
        $e_type = Html::escape($args_raw[$e_type_arg]);
      }
    }

    $configured_e_types = $grant_configs['entities'];
    if (!\array_key_exists($e_type, $configured_e_types)) {
      return FALSE;
    }

    $check = 'perm';
    $check_perm = '';
    $check_roles = [];
    if (isset($options['grant_perm'])) {
      if (\is_array($options['grant_perm'])) {
        // Transform to 'OR' Logic:
        $check_perm = (string) implode('+', $options['grant_perm']);
      }
      else {
        $check_perm = $options['grant_perm'];
      }
    }
    else {
      $check = 'role';
      if (\is_string($options['grant_role'])) {
        $check_roles = explode('+', $options['grant_role']);
      }
      else {
        $check_roles = array_keys($options['grant_role']);
      }
    }

    $e_id_arg = $options['e_id_arg'] ?? 2;

    $e_id_raw = '_none';
    $e_id = 0;
    $e_uuid = NULL;

    if (isset($args_raw[$e_id_arg])) {
      $e_id_raw = $args_raw[$e_id_arg];
      if ($options['e_id_type'] == 'uuid') {
        if (Uuid::isValid($e_id_raw)) {
          $e_uuid = $e_id_raw;
        }
        else {
          return FALSE;
        }
      }
      else {
        $e_id = (int) $e_id_raw;
      }
    }

    if ($account == NULL) {
      $account = $this->account;
    }

    // First check global roles or permissions:
    switch ($check) {
      case 'role':
        $access = !empty(array_intersect(array_filter($check_roles), $account->getRoles()));
        break;

      case 'perm':
        $access = $account->hasPermission($check_perm);
        break;

    }

    if ($access) {
      return $access;
    }

    $uid = $account->id();
    $user = $this->entityTypeManager->getStorage('user')->load($uid);
    $u3id = $user->uuid();

    if ($e_uuid == NULL) {
      $entity = $this->entityTypeManager->getStorage($e_type)->load($e_id);
      if ($entity instanceof ContentEntityInterface) {
        $e_uuid = $entity->uuid();
      }
      else {
        return FALSE;
      }
    }

    switch ($check) {
      case 'role':
        $uag_roles = $this->getUserAssignedGrantRoles($u3id, $e_type, $e_uuid);
        $access = !empty(array_intersect(array_filter($check_roles), $uag_roles));
        break;

      case 'perm':
        $access = $this->userAssignedGrantHasPermission($u3id, $check_perm, $e_type, $e_uuid);
        break;
    }

    return $access;
  }

  /**
   * {@inheritdoc}
   */
  public function getUserAssignedGrantRoles($u3id = 'current', $e_type = '', $e_uuid = '') {
    if ($u3id == 'current') {
      $uid = $this->account->id();
      $user = $this->entityTypeManager->getStorage('user')->load($uid);
      $u3id = $user->uuid();
    }
    $uag_roles = [];

    $uag = $this->getUserAssignedGrants($u3id);

    $data = $this->getUserAssignedGrantEntitiesRoles(
      [
        'grant_config' => $this->getGrantConfigs(),
        'uag_roles' => $uag_roles,
        'uag' => $uag,
        'e_type' => $e_type,
        'e_uuid' => $e_uuid,
        'e_processed' => [],
        'counter' => 0,
      ]);
    return $data['uag_roles'];
  }

  /**
   * {@inheritdoc}
   */
  public function userAssignedGrantHasPermission($u3id = 'current', $perm_raw = '', $e_type = '', $e_uuid = '', $role_limit = [], $uag_roles = []) {
    if ($u3id == 'current') {
      $uid = $this->account->id();
      $user = $this->entityTypeManager->getStorage('user')->load($uid);
      $u3id = $user->uuid();
    }
    if ($uag_roles == []) {
      $uag_roles = $this->getUserAssignedGrantRoles($u3id, $e_type, $e_uuid);
    }

    // @todo Check if this experimental can be remeoved.
    if ($role_limit != []) {
      // Only check permission if there is no role limitation:
      $role_limit_test = FALSE;
      foreach ($role_limit as $test_role) {
        if (in_array($test_role, $uag_roles)) {
          $role_limit_test = TRUE;
          continue;
        }
      }
      if ($role_limit_test == FALSE) {
        return FALSE;
      }
    }
    $rolestorage = $this->entityTypeManager->getStorage('user_role');

    // Logic from "/core/modules/user/src/Access/PermissionAccessCheck.php":
    $conjunction = 'AND';
    $split = explode(',', $perm_raw);
    if (count($split) > 1) {
      $conjunction = 'AND';
    }
    else {
      $split = explode('+', $perm_raw);
      $conjunction = 'OR';
    }
    // Logic from "/core/lib/Drupal/Core/Access/AccessResult.php":
    $access = FALSE;
    if ($conjunction == 'AND') {
      $access = TRUE;
      foreach ($split as $permission) {
        if (!$rolestorage->isPermissionInRoles($permission, $uag_roles)) {
          $access = FALSE;
          break;
        }
      }
    }
    else {
      foreach ($split as $permission) {
        if ($rolestorage->isPermissionInRoles($permission, $uag_roles)) {
          $access = TRUE;
          break;
        }
      }
    }
    return $access;
  }

  /**
   * Retrieve user assigned grants roles of entities incl. parent entities.
   */
  private function getUserAssignedGrantEntitiesRoles($data) {
    $grant_config = $data['grant_config'];
    $data['counter']++;

    if (isset($data['e_processed']['e_type'])
      && isset($data['e_processed']['e_uuid'])) {
      return $data;
    }
    $uag = $data['uag'];
    $e_type = $data['e_type'];
    $e_uuid = $data['e_uuid'];
    $uag_roles_entity = [];
    if (isset($uag[$e_type]) && isset($uag[$e_type][$e_uuid])) {
      $uag_roles_entity = array_keys($uag[$e_type][$e_uuid]);
      $data['e_processed'][$e_type][$e_uuid] = $uag_roles_entity;
    }
    $data['uag_roles'] = array_merge($uag_roles_entity, $data['uag_roles']);

    // Check if current entity type has referenced parent fields defined.
    if (isset($grant_config['entities'][$e_type])) {

      $entity = $this->entityLoadUuid($e_type, $e_uuid);
      if ($entity instanceof ContentEntityInterface) {
        /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
        $bundle = $entity->bundle();

        $parent_fields = $grant_config['entities'][$e_type][$bundle]['assign_parents'] ?? [];
        if ($parent_fields != []) {
          $fields = $entity->getFields();
          // Only loop through referenced parent fields.
          foreach ($parent_fields as $parent_field) {

            if (isset($fields[$parent_field])) {

              $field = $fields[$parent_field];
              $data['e_type'] = $field->getSetting('target_type');
              $values = $field->getValue();
              foreach ($values as $value) {
                if (isset($value['target_uuid'])) {
                  $data['e_uuid'] = $value['target_uuid'];
                }
                else {
                  $data['e_uuid'] = "0";
                  if (isset($value['target_id'])) {
                    $target = $this->entityTypeManager
                      ->getStorage($data['e_type'])
                      ->load($value['target_id']);
                    if ($target) {
                      $data['e_uuid'] = $target->uuid();
                    }
                  }
                }

                if ($data['counter'] < $grant_config['max_deph']) {
                  // Self calling this function.
                  $data = $this->getUserAssignedGrantEntitiesRoles($data);
                }
                else {
                  // Max deph reached.
                  // @todo Log and/or set message to inform admin.
                }
              }
            }
          }
        }
      }
    }
    return $data;
  }

  /**
   * {@inheritdoc}
   */
  public function getUserAssignedGrants($uuid = "current") {
    if ($uuid == "current") {
      $current_user_id = $this->account->id();
      $current_user = $this->entityTypeManager->getStorage('user')->load($current_user_id);
      $uuid = $current_user->uuid();
    }
    $cache_id = 'grant_uag:' . $uuid;
    $cached = $this->cacheBackend->get($cache_id);
    if ($cached) {
      $grants = $cached->data;
    }
    else {
      $grants = [];
      $grant_storage = $this->entityTypeManager->getStorage('grant');

      $grant_query = $grant_storage->getQuery()
        ->accessCheck(FALSE)
        ->condition('assignee', $uuid)
        ->condition('status', 1);
      $grant_entities = $grant_storage->loadMultiple($grant_query->execute());
      foreach ($grant_entities as $grant) {
        /** @var \Drupal\grant\Entity\Grant $grant */
        $role = $grant->get('role')->target_id;
        $entity_type = $grant->get('entity_type')->value;
        $entity_uuid = $grant->get('entity_uuid')->value;
        $grants[$entity_type][$entity_uuid][$role] = $grant->get('uuid')->value;
      }
      // @todo Add cache tag for entity_type and user.
      $cache_tags = ['grant_uag', 'grant:' . $uuid];
      $this->cacheBackend->set($cache_id, $grants, CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
    }
    return $grants;
  }

  /**
   * Retrieve user mail addresses.
   */
  private function getUserEmails($uid = 0) {
    $current_user_id = $this->account->id();
    $current = FALSE;
    if ($uid == 0) {
      $uid = $current_user_id;
      $current = TRUE;
    }
    $emails = [];
    if ($this->moduleHandler->moduleExists('multiple_email')) {
      $email_storage = $this->entityTypeManager->getStorage('multiple_email');
      $multiple_email_query = $email_storage->getQuery()
        ->accessCheck(FALSE)
        ->condition('uid', $uid)
        ->condition('status', EmailInterface::CONFIRMED);
      $email_entities = $email_storage->loadMultiple($multiple_email_query->execute());

      foreach ($email_entities as $email_entity) {
        /** @var \Drupal\multiple_email\Entity\Email $email_entity */
        $emails[] = $email_entity->getEmail();
      }
    }
    else {
      if ($current) {
        $user = $this->account;
      }
      else {
        $user = $this->entityTypeManager->getStorage('user')->load($uid);
      }
      /** @var \Drupal\user\Entity\User $user */
      $emails[] = $user->getEmail();
    }
    return $emails;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc