Commit 7f101757 authored by Pravin Gaikwad's avatar Pravin Gaikwad
Browse files

Issue #2931143 by Rajeshreeputra, stefan.korn, TrevorBradley, tim-diels,...

Issue #2931143 by Rajeshreeputra, stefan.korn, TrevorBradley, tim-diels, ezeedub, ngkoutsaik, awm, emek, kbrodej, guilhermevp, szhu, S3b0uN3t: Permissions per role per entity bundle
parent 403c18ff
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -148,7 +148,11 @@ function entity_clone_entity_access(EntityInterface $entity, $operation, Account
  $cache->addCacheContexts(['user.permissions']);

  // Deny access if the user cannot clone the entity.
  $access = AccessResult::forbiddenIf(!$account->hasPermission('clone ' . $entity->getEntityTypeId() . ' entity'));
  $access = AccessResult::forbiddenIf(
    !$account->hasPermission('clone ' . $entity->getEntityTypeId() . ' entity')
    &&
    !$account->hasPermission('clone ' . $entity->bundle() . ' '. $entity->getEntityTypeId() . ' entities')
  );
  if ($access->isForbidden()) {
    return $access->addCacheableDependency($cache);
  }
+7 −0
Original line number Diff line number Diff line
name: 'Entity Clone Extras'
type: module
description: 'Allow for bundle-level permissions for Node (and Media) entity types'
core_version_requirement: ^8 || ^9 || ^10
package: 'Entity Clone'
dependencies:
  - drupal:entity_clone
+78 −0
Original line number Diff line number Diff line
<?php

/**
 * @file
 * Contains entity_clone_extras.module.
 */

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;

/**
 * Implements hook_help().
 */
function entity_clone_extras_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    // Main module help for the entity_clone_extras module.
    case 'help.page.entity_clone_extras':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Allow for bundle-level permissions for Node (and Media) entity types') . '</p>';
      return $output;

    default:
  }
}

/**
 * Implements hook_entity_operation_alter().
 */
function entity_clone_extras_entity_operation_alter(array &$operations, EntityInterface $entity) {
  // Check if entity type supports cloning:
  if ($entity->hasLinkTemplate('clone-form')) {
    // If it does, get the current user.
    $user = \Drupal::currentUser();
    $entity_types = _entity_clone_extra_supported_entity_types();
    if (in_array($entity->getEntityTypeId(), $entity_types)) {
      if (!$user->hasPermission('clone ' . $entity->getEntityTypeId() . ' entity')) {
        // If we are dealing with a supported entity type, we handle permissions
        // per bundle.
        $bundle = $entity->bundle();
        $entity_type = $entity->getEntityTypeId();
        // Check the bundle access.
        if (!$user->hasPermission("clone $bundle $entity_type entities")) {
          // Remove the operation if the user has no access to it.
          unset($operations['clone']);
        }
      }
    }
  }
}

/**
 * Implements hook_entity_access().
 */
function entity_clone_extras_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
  $entity_types = _entity_clone_extra_supported_entity_types();
  if ($operation === 'clone' && in_array($entity->getEntityTypeId(), $entity_types)) {
    return AccessResult::allowedIfHasPermission($account, 'clone ' . $entity->bundle() . ' ' . $entity->getEntityTypeId() . ' entities');
  }
  return AccessResult::neutral();
}

/**
 * Define the supported entity types.
 *
 * @return string[]
 *   The entity types.
 */
function _entity_clone_extra_supported_entity_types() {
  $entity_types = ['node'];
  // Support media entities when media module is installed.
  if (\Drupal::moduleHandler()->moduleExists('media')) {
    $entity_types[] = 'media';
  }
  return $entity_types;
}
+2 −0
Original line number Diff line number Diff line
permission_callbacks:
  - Drupal\entity_clone_extras\EntityCloneExtrasPermissions::permissions
+102 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\entity_clone_extras;

use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\StringTranslation\TranslationManager;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides dynamic permissions of the entity_clone module.
 */
class EntityCloneExtrasPermissions implements ContainerInjectionInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The string translation manager.
   *
   * @var \Drupal\Core\StringTranslation\TranslationManager
   */
  protected $translationManager;

  /**
   * Module Handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * Constructs a new EntityCloneExtrasPermissions instance.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager
   *   The entity type manager.
   * @param \Drupal\Core\StringTranslation\TranslationManager $string_translation
   *   The string translation manager.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   Module handler.
   */
  public function __construct(EntityTypeManagerInterface $entity_manager, TranslationManager $string_translation, ModuleHandlerInterface $module_handler) {
    $this->entityTypeManager = $entity_manager;
    $this->translationManager = $string_translation;
    $this->moduleHandler = $module_handler;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('string_translation'),
      $container->get('module_handler')
    );
  }

  /**
   * Returns an array of entity_clone_extras permissions.
   *
   * @return array
   *   The permission list.
   */
  public function permissions() {
    $permissions = [];
    // Fetch all available content types.
    $content_types = $this->entityTypeManager->getStorage('node_type')
      ->loadMultiple();
    foreach ($content_types as $key => $type) {
      // Add a permission to clone each content type.
      $permissions['clone ' . $key . ' node entities'] = $this
        ->translationManager
        ->translate('Clone all <em>@label</em> node entities', [
          '@label' => $type->label(),
        ]);
    }

    // Support media entities when media module is installed.
    if ($this->moduleHandler->moduleExists('media')) {
      // Fetch all available media types.
      $media_types = $this->entityTypeManager->getStorage('media_type')
        ->loadMultiple();
      foreach ($media_types as $key => $type) {
        // Add a permission to clone each media type.
        $permissions['clone ' . $key . ' media entities'] = $this
          ->translationManager
          ->translate('Clone all <em>@label</em> media entities', [
            '@label' => $type->label(),
          ]);
      }
    }

    return $permissions;
  }

}