foldershare-8.x-1.2/src/Entity/FolderShareAccessControlHandler.php

src/Entity/FolderShareAccessControlHandler.php
<?php
 
namespace Drupal\foldershare\Entity;
 
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
 
use Drupal\foldershare\Constants;
use Drupal\foldershare\FolderShareInterface;
 
/**
 * Provides access control for operations on files and folders.
 *
 * Access to a folder and its files is controlled by three mechanisms:
 *
 * - Permission-based access control.
 * - Root item-based access control.
 * - Module settings to enable/disable sharing for the entire site.
 *
 * <B>Permission-based access control</B>
 * The module uses the standard Drupal role-based permissions mechanism and
 * these module-specific permissions:
 *
 * - "view foldershare" enables users to view and download content.
 *
 * - "author foldershare" enables users to create, delete, and modify content.
 *
 * - "share foldershare" enables users to share root items with other users.
 *
 * - "share public foldershare" enables users to share root items with the
 *   public (anonymous users).
 *
 * - "administer foldershare" enables users to modify anyone's content,
 *   change content ownership, or modify content share settings.
 *
 * Additionally, users designated as site administrators always have
 * full access to all content regardless of permissions.
 *
 * <B>Root item-based access control</B>
 * Root items have access control lists that designate specific users
 * that may view and author content. These access control lists act as a
 * boolean AND with permission access controls so that a user must have
 * both the site-wide generic view permission AND a root item's view
 * access grant in order to view content.
 *
 * Content owners are always included in the access control lists of their
 * own content and therefore always have full view and author access.
 *
 * The generic "anonymous" user may be granted access as well. This
 * publishes content for public access.
 *
 * Access grants are always on the root item of a folder tree, and they
 * apply to all content within that folder tree.
 *
 * <B>Warning:</B> This class is strictly internal to the FolderShare
 * module. The class's existance, name, and content may change from
 * release to release without any promise of backwards compatability.
 *
 * @ingroup foldershare
 *
 * @see \Drupal\foldershare\Entity\FolderShare
 */
class FolderShareAccessControlHandler extends EntityAccessControlHandler {
 
  /*---------------------------------------------------------------------
   *
   * Field view and edit access.
   *
   *---------------------------------------------------------------------*/
 
  /**
   * Fields that should never be viewed.
   *
   * These are internal fields that don't have a meaningful presentation
   * and should NEVER be shown on a page.
   *
   * Note that we *do not* exclude the module's internal parentid and
   * rootid fields. While these are not something users should normally
   * view directly, there is nothing wrong with doing so.
   */
  const FIELDS_VIEW_NEVER = [
    'langcode',
    'uuid',
  ];
 
  /**
   * Fields that should never be edited directly.
   *
   * These are internal fields with values set programmatically. They
   * should NEVER be edited directly by a user. There are, however,
   * entity API calls that can set these while maintaining the integrity
   * of the data model.
   *
   * The 'id' and 'uuid' are assigned by Drupal and need to remain unchanged
   * for the life of the entity.
   *
   * The 'uid' is the owner of the content and should not be edited
   * directly.
   *
   * The 'parentid and 'rootid are internal fields used to connect folders
   * into a folder hierarchy. They are only changed when content is moved
   * from place to place in the hierarchy.
   *
   * The 'size' is computed automatically and should never be edited.
   *
   * The 'kind' field indicates whether the entity is a file or folder
   * and should never be edited.
   *
   * The 'file' field gives the entity ID of an underlying File object,
   * if any, and obviously should never be edited.
   *
   * The 'grantauthoruids' and 'grantviewuids' store the user IDs of users
   * granted specific access to view or author content in a root folder.
   * None of these should be edited.
   */
  const FIELDS_EDIT_NEVER = [
    'id',
    'uid',
    'uuid',
    'created',
    'changed',
    'langcode',
    'parentid',
    'rootid',
    'size',
    'kind',
    'mime',
    'file',
    'image',
    'media',
    'grantauthoruids',
    'grantviewuids',
    'systemhidden',
    'systemdisabled',
  ];
 
  /*---------------------------------------------------------------------
   *
   * Construct.
   *
   *---------------------------------------------------------------------*/
 
  /**
   * Constructs and initializes an access control handler object.
   *
   * @param \Drupal\Core\Entity\EntityTypeInterface $entityType
   *   The entity type definition.
   */
  public function __construct(EntityTypeInterface $entityType) {
    parent::__construct($entityType);
 
    // File and folder names (labels) may be viewed by users granted
    // permission using the generic view operation.
    $this->viewLabelOperation = FALSE;
  }
 
  /**
   * {@inheritdoc}
   */
  public static function createInstance(EntityTypeInterface $entityType) {
    return new static($entityType);
  }
 
  /*---------------------------------------------------------------------
   *
   * Check access.
   *
   * Implements EntityAccessControlHandler and overrides selected methods.
   *
   * These are the primary entrance points for this class.
   *
   *---------------------------------------------------------------------*/
 
  /**
   * Checks if a user has permission for an operation on an item.
   *
   * The following operations are supported:
   *
   * - 'chown'. Change ownership of the file or folder and all of its contents.
   *
   * - 'delete'.  Delete the file or folder, and all of its subfolders
   *   and files.
   *
   * - 'share'.  Change access grants to share/unshare a root item, and
   *   its folder tree, for view or author access by other users.
   *
   * - 'update'.  Edit the file's or folder's fields.
   *
   * - 'view'.  View or copy the file's or folder's fields.
   *
   * <B>Hooks</B>
   * Via the parent class, this method invokes the "hook_foldershare_access"
   * hook after checking permissions and access grants. This hook is not
   * invoked for administrators, which always have access.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity for which access checking is required.
   * @param string $operation
   *   The name of the operation being considered.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   (optional) The user for which to check access.  Defaults to the
   *   current user.
   * @param bool $returnAsObject
   *   (optional) When TRUE, an access object is returned. When FALSE
   *   (default), a boolean is returned.
   *
   * @return bool|\Drupal\Core\Access\AccessResultInterface
   *   The result of the access control check.
   *
   * @see ::checkAccess()
   */
  public function access(
    EntityInterface $entity,
    $operation,
    AccountInterface $account = NULL,
    $returnAsObject = FALSE) {
 
    // This method, and those it calls, implement four steps for access
    // control:
    //
    // 1. If the user is a site or content administrator, they are granted
    //    immediate access for all content and all operations.
    //
    // 2. If the user does not have the specific module permission required
    //    for an operation (e.g. view, author, share), they are denied
    //    access.
    //
    // 3. If the user does not own the content and sharing is disabled for
    //    the module, they are denied access.
    //
    // 4. If the user does not own the content and they are not granted
    //    specific access by the content's root item, they are denied
    //    access.
    //
    // Otherwise the user is granted access.
    //
    // This method handles step (1) only. It then forwards to the parent
    // class, which forwards to our checkAccess() method below which
    // handles steps (2), (3), and (4).
    $account = $this->prepareUser($account);
 
    //
    // Allow site & content administrators everything.
    // -----------------------------------------------
    // Drupal insures that users marked as site administrators always have
    // all permissions. The check below, then, will always return TRUE for
    // site admins.
    //
    // Content administrators have this module's ADMINISTER_PERMISSION,
    // which grants them access to all content for all operations.
    $perm = $this->entityType->getAdminPermission();
    if (empty($perm) === TRUE) {
      $perm = Constants::ADMINISTER_PERMISSION;
    }
 
    $access = AccessResult::allowedIfHasPermission($account, $perm);
    if ($access->isAllowed() === TRUE) {
      // The user is either a site admin or they have the module's
      // content admin permission. Grant full access.
      $access->cachePerPermissions();
      return $returnAsObject === TRUE ? $access : $access->isAllowed();
    }
 
    //
    // Check entity-based ACLs.
    // ------------------------
    // At this point, the user is NOT a site administrator and they do not
    // have module content admin permission. Access to the content is
    // determined now by a mix of permissions, module settings, and content
    // access controls.
    //
    // Forward to the parent class, which implements cache checks and
    // module hooks to override access controls. Afterwards the parent
    // calls our checkAccess() method to handle permissions and root item
    // access control lists.
    $access = parent::access($entity, $operation, $account, TRUE);
    $access->cachePerPermissions();
    return $returnAsObject === TRUE ? $access : $access->isAllowed();
  }
 
  /**
   * Checks if a given user has permission to create a new entity.
   *
   * This method handles access checks for create operations.
   * Access is granted for creating root items if:
   *
   * - The user has the administer permission OR
   * - The user has the author permission.
   *
   * Note that this method is NOT passed an entity, so it cannot check
   * if creation is allowed within an entity. To do that, use access()
   * on the entity and pass 'create' as the operation.
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   (optional, default = NULL = current user) The user for which to
   *   check access.
   * @param array $context
   *   (optional, default = []) An array of key-value pairs to pass additional
   *   context to this method. Ignored by this method.
   * @param string|null $bundle
   *   (optional, default = NULL) An optional bundle of the entity, for
   *   entities that support bundles, and NULL otherwise.  Ignored by this
   *   method since file/folder entities do not support bundles.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The result of the access control check.
   *
   * @see ::checkAccess()
   */
  protected function checkCreateAccess(
    AccountInterface $account = NULL,
    array $context = [],
    $bundle = NULL) {
 
    $account = $this->prepareUser($account);
 
    //
    // Allow site & content administrators everything.
    // -----------------------------------------------
    // Drupal insures that users marked as site administrators always have
    // all permissions. The check below, then, will always return TRUE for
    // site admins.
    //
    // Content administrators have this module's ADMINISTER_PERMISSION,
    // which grants them access to everything.
    $perm = $this->entityType->getAdminPermission();
    if (empty($perm) === TRUE) {
      $perm = Constants::ADMINISTER_PERMISSION;
    }
 
    $access = AccessResult::allowedIfHasPermission($account, $perm);
    if ($access->isAllowed() === TRUE) {
      // The user is either a site admin or they have the module's
      // content admin permission. Access granted.
      $access->cachePerPermissions()
        ->cachePerUser();
      return $access;
    }
 
    //
    // Allow author users.
    // -------------------
    // Require AUTHOR_PERMISSION.
    $perm = Constants::AUTHOR_PERMISSION;
    $access = AccessResult::allowedIfHasPermission($account, $perm);
    if ($access->isAllowed() === FALSE) {
      // Access denied.
      return AccessResult::forbidden()
        ->cachePerPermissions()
        ->cachePerUser();
    }
 
    return AccessResult::allowed()
      ->cachePerPermissions()
      ->cachePerUser();
  }
 
  /**
   * Checks if a user has permission to view or edit a field.
   *
   * If the entity allows access (based on permissions and root item
   * access grants), then most fields may be viewed and some may be
   * edited. Some internal fields may be viewed by administrators,
   * but not edited directly.
   *
   * The table below indicates which fields are restricted.
   * The fields themselves are defined in the FolderShare class.
   *
   * | Field            | Allow for view | Allow for edit |
   * | ---------------- | -------------- | -------------- |
   * | id               | yes            | no             |
   * | uuid             | yes            | no             |
   * | uid              | yes            | no             |
   * | langcode         | no             | yes            |
   * | created          | yes            | no             |
   * | changed          | yes            | no             |
   * | size             | yes            | no             |
   * | name             | yes            | yes            |
   * | description      | yes            | yes            |
   * | parentid         | yes            | no             |
   * | rootid           | yes            | no             |
   * | kind             | yes            | no             |
   * | file             | yes            | no             |
   * | grantauthoruids  | yes            | no             |
   * | grantviewuids    | yes            | no             |
   * | systemhidden     | no             | no             |
   * | systemdisabled   | no             | no             |
   *
   * Any additional fields created by third-parties or by the field_ui
   * module can be viewed and edited.
   *
   * @param string $operation
   *   The name of the operation being considered, which is always
   *   'view' or 'edit' (defined by Drupal core).
   * @param \Drupal\Core\Field\FieldDefinitionInterface $field
   *   The field being checked.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   (optional) The user for which to check access.  Defaults to
   *   the current user.
   * @param \Drupal\Core\Field\FieldItemListInterface $items
   *   (optional) The list of field values for which to check access.
   *   Ignored by this method.
   *
   * @return\Drupal\Core\Access\AccessResultInterface
   *   The result of the access control check.
   */
  protected function checkFieldAccess(
    $operation,
    FieldDefinitionInterface $field,
    AccountInterface $account = NULL,
    FieldItemListInterface $items = NULL) {
 
    // This method is called for every field of every row when showing
    // lists of files and folders. It is therefore important that it run as
    // quickly as possible for view operations.
    $fieldName = $field->getName();
    switch ($operation) {
      case 'view':
        // Any field in FIELDS_VIEW_NEVER is NEVER viewable by any type
        // of user, including admins.
        if (in_array($fieldName, self::FIELDS_VIEW_NEVER, TRUE) === TRUE) {
          // Access denied.
          return AccessResult::forbidden();
        }
 
        // Access granted.
        return AccessResult::allowed();
 
      case 'edit':
        // Any field in FIELDS_EDIT_NEVER is NEVER editable directly by
        // any type of user, including admins.
        if (in_array($fieldName, self::FIELDS_EDIT_NEVER, TRUE) === TRUE) {
          // Access denied.
          return AccessResult::forbidden();
        }
 
        // Access granted.
        return AccessResult::allowed();
 
      default:
        // Unknown operation. Access denied.
        return AccessResult::forbidden();
    }
  }
 
  /**
   * Checks if a user can do an operation on an item.
   *
   * This is the principal access control method for this class. It
   * checks permissions and per-root item access control lists to decide
   * if access is granted or denied.
   *
   * The following operations are supported:
   *
   * - 'create'.  Create a new item within a folder.
   *
   * - 'delete'.  Delete the file or folder, and all its subfolders and files.
   *
   * - 'share'.  Change access grants to share/unshare
   *   this item's root item for view or author access by other users.
   *
   * - 'update'.  Edit the file's or folder's fields or add children to
   *   a folder.
   *
   * - 'view'.  View and copy the file's or folder's fields.
   *
   * Each of these operations require an appropriate mix of module
   * permissions, file/folder ownership, and/or access grants:
   *
   * - Create requires that the user have module author permission AND
   *   either own the file/folder OR have been granted author access
   *   on the root item.
   *
   * - Delete requires that the user have module author permission AND
   *   either own the file/folder OR have been granted author access
   *   on the root item.
   *
   * - Share requires that the user have module share permission AND
   *   own the file/folder's root item, where access grants are stored.
   *
   * - Update requires that the user have module author permission AND
   *   either own the file/folder OR have been granted author access
   *   on the root item.
   *
   * - View requires that the user have module view permission AND
   *   either own the file/folder OR have been granted view access
   *   on the root item.
   *
   * - View tree requires that the user have module view permission AND
   *   either own the entire folder tree OR have been granted view access
   *   on the root item.
   *
   * Note that update and delete only check the file/folder for access and
   * NOT all subfolders. This means that a user that is allowed to write to
   * a file/folder, can delete that file/folder and all of its contents,
   * even if they do not have write permission on all of that content.
   * Ownership of a file/folder is always an override of the per-file/folder
   * access controls.
   *
   * @param \Drupal\Core\Entity\EntityInterface $item
   *   The entity for which access checking is required.
   * @param string $operation
   *   The name of the operation being considered.
   * @param \Drupal\Core\Session\AccountInterface $user
   *   (optional) The user for which to check access.  Defaults to
   *   the current user.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The result of the access control check.
   */
  protected function checkAccess(
    EntityInterface $item,
    $operation,
    AccountInterface $user = NULL) {
 
    //
    // Validate.
    // ---------
    // If the given entity is missing or invalid, we cannot check access.
    if ($item === NULL) {
      // No entity. Access denied.
      return AccessResult::forbidden();
    }
 
    $entityTypeId = $item->getEntityTypeId();
    if ($entityTypeId !== FolderShare::ENTITY_TYPE_ID) {
      // Invalid entity. Access denied.
      return AccessResult::forbidden();
    }
 
    // Get current user info.
    $user = $this->prepareUser($user);
    $userId = (int) $user->id();
 
    //
    // Allow site & content administrators everything.
    // -----------------------------------------------
    // Drupal insures that users marked as site administrators always have
    // all permissions. The check below, then, will always return TRUE for
    // site admins.
    //
    // Content administrators have this module's ADMINISTER_PERMISSION,
    // which grants them access to everything.
    $perm = $this->entityType->getAdminPermission();
    if (empty($perm) === TRUE) {
      $perm = Constants::ADMINISTER_PERMISSION;
    }
 
    $access = AccessResult::allowedIfHasPermission($user, $perm);
    if ($access->isAllowed() === TRUE) {
      // The user is either a site admin or they have the module's
      // content admin permission. Access granted.
      $access->cachePerPermissions()
        ->cachePerUser();
      return $access;
    }
 
    //
    // Check for disabled and hidden.
    // ------------------------------
    // Disabled and hidden items are never accessible.
    if ($item->isSystemHidden() === TRUE) {
      return AccessResult::forbidden()
        ->cachePerPermissions()
        ->cachePerUser()
        ->addCacheableDependency($item);
    }
 
    if ($item->isSystemDisabled() === TRUE) {
      return AccessResult::forbidden()
        ->cachePerPermissions()
        ->cachePerUser()
        ->addCacheableDependency($item);
    }
 
    //
    // Check access.
    // -------------
    // For each known operation, check permissions and per-root item access
    // control grants.
    switch ($operation) {
      case 'view':
      case 'update':
      case 'delete':
      case 'create':
        // View, update, delete, or create-within content.
        //
        // Allowed if:
        // - User has view/update/delete permission.
        // - And one of:
        //   - User owns the content.
        //   - Owner has sharing permission AND
        //     user has been granted appropriate view or author access.
        if ($operation === 'view') {
          // View.
          $userPermissionNeeded = Constants::VIEW_PERMISSION;
          $userGrantNeeded = 'view';
        }
        elseif ($operation === 'create') {
          // Create. If the item is not a folder, then forbidden.
          if ($item->isFolder() === FALSE) {
            return AccessResult::forbidden()
              ->cachePerPermissions()
              ->cachePerUser()
              ->addCacheableDependency($item);
          }
 
          $userPermissionNeeded = Constants::AUTHOR_PERMISSION;
          $userGrantNeeded = 'author';
        }
        else {
          // Update and delete.
          $userPermissionNeeded = Constants::AUTHOR_PERMISSION;
          $userGrantNeeded = 'author';
        }
 
        // Check that the current user has permission.
        $access = AccessResult::allowedIfHasPermission(
          $user,
          $userPermissionNeeded);
 
        if ($access->isAllowed() === FALSE) {
          // Access denied. The user does not have the required permissions.
          return $access->cachePerPermissions()
            ->cachePerUser()
            ->addCacheableDependency($item);
        }
 
        // Check if the root item is hidden or disabled.
        $rootItem = $item->getRootItem();
        if ($rootItem->isSystemHidden() === TRUE ||
            $rootItem->isSystemDisabled() === TRUE) {
          return AccessResult::forbidden()
            ->cachePerPermissions()
            ->cachePerUser()
            ->addCacheableDependency($item)
            ->addCacheableDependency($rootItem);
        }
 
        // Check if the root item's owner has explicitly granted shared
        // access to the current user.
        if ($rootItem->isAccessGranted($userId, $userGrantNeeded) === FALSE) {
          // Access denied. The item is not owned by the current user and
          // the owner of the item's root has not granted the user access.
          return AccessResult::forbidden()
            ->cachePerPermissions()
            ->cachePerUser()
            ->addCacheableDependency($item)
            ->addCacheableDependency($rootItem);
        }
 
        // Success!
        return $access->cachePerPermissions()
          ->cachePerUser()
          ->addCacheableDependency($item)
          ->addCacheableDependency($rootItem);
 
      case 'share':
        // Share content.
        //
        // Allowed if:
        // - User has share permission.
        // - User owns the root item.
        //
        // Never allowed for anonymous.
        if ($user->isAnonymous() === TRUE) {
          return AccessResult::forbidden()
            ->cachePerPermissions()
            ->cachePerUser()
            ->addCacheableDependency($item);
        }
 
        $access = AccessResult::allowedIfHasPermission(
          $user,
          Constants::SHARE_PERMISSION);
 
        if ($access->isAllowed() === FALSE) {
          $access = AccessResult::allowedIfHasPermission(
            $user,
            Constants::SHARE_PUBLIC_PERMISSION);
 
          if ($access->isAllowed() === FALSE) {
            // Access denied. The user does not have the required permissions.
            return $access->cachePerPermissions()
              ->cachePerUser()
              ->addCacheableDependency($item);
          }
        }
 
        // Check if the root item is hidden or disabled.
        $rootItem = $item->getRootItem();
        if ($rootItem->isSystemHidden() === TRUE ||
            $rootItem->isSystemDisabled() === TRUE) {
          return AccessResult::forbidden()->cachePerPermissions()
            ->cachePerUser()
            ->addCacheableDependency($item)
            ->addCacheableDependency($rootItem);
        }
 
        // Check if the item is owned by the current user.
        $rootOwnerId = (int) $rootItem->getOwnerId();
        if ($rootOwnerId !== $userId) {
          // Access denied. The current user does not own the item, so they
          // cannot change its sharing grants.
          return AccessResult::forbidden()->cachePerPermissions()
            ->cachePerUser()
            ->addCacheableDependency($item)
            ->addCacheableDependency($rootItem);
        }
 
        // Success!
        return $access->cachePerPermissions()
          ->cachePerUser()
          ->addCacheableDependency($item)
          ->addCacheableDependency($rootItem);
 
      case 'chown':
        // Only site or module content administrators may change ownership
        // on content. Above we already checked for admins and granted access
        // to them. So if we are here, the user is not an admin and access
        // denied.
        return AccessResult::forbidden()
          ->cachePerPermissions()
          ->cachePerUser()
          ->addCacheableDependency($item);
 
      default:
        // Unknown operation. Access denied.
        return AccessResult::forbidden()
          ->cachePerPermissions()
          ->cachePerUser()
          ->addCacheableDependency($item);
    }
  }
 
  /**
   * Checks if a user has permission for an operation.
   *
   * The following operations are supported:
   *
   * - 'chown'
   * - 'delete'
   * - 'share'
   * - 'update'
   * - 'view'
   *
   * Unlike access(), this function only checks permissions, and not
   * entity-based access controls. It therefore returns the *potential*
   * for access, but not an absolute yes/no on access because that
   * would require checking entity access controls too for a specific
   * file or folder.
   *
   * @param string $operation
   *   The name of the operation being considered.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   (optional) The user for which to check access.  Defaults to
   *   the current user.
   *
   * @return bool
   *   The result of the access control check.
   */
  public static function mayAccess(
    string $operation,
    AccountInterface $account = NULL) {
 
    //
    // Validate.
    // ---------
    // Get the account to check.
    if ($account === NULL) {
      $account = \Drupal::currentUser();
    }
 
    //
    // Allow site & content administrators everything.
    // -----------------------------------------------
    // Drupal insures that users marked as site administrators always have
    // all permissions. The check below, then, will always return TRUE for
    // site admins.
    //
    // Content administrators have this module's ADMINISTER_PERMISSION,
    // which grants them access to everything.
    if ($account->hasPermission(Constants::ADMINISTER_PERMISSION) === TRUE) {
      // The user is either a site admin or they have the module's
      // content admin permission. Access granted.
      return TRUE;
    }
 
    //
    // Check permissions.
    // ------------------
    // For each known operation, check permissions only.
    switch ($operation) {
      case 'view':
        // View content.
        return $account->hasPermission(Constants::VIEW_PERMISSION);
 
      case 'update':
      case 'delete':
      case 'create':
        // Change or delete content.
        return $account->hasPermission(Constants::AUTHOR_PERMISSION);
 
      case 'share':
        // Alter sharing of content.
        if ($account->isAnonymous() === TRUE) {
          // Anonymous NEVER has share permission.
          return FALSE;
        }
 
        return $account->hasPermission(Constants::SHARE_PERMISSION) ||
          $account->hasPermission(Constants::SHARE_PUBLIC_PERMISSION);
 
      case 'chown':
        // Only administrators can change ownership, which was already
        // checked above. Access denied.
        return FALSE;
 
      default:
        // Unrecognized operation. Access denied.
        return FALSE;
    }
  }
 
  /**
   * Returns a list of operations and their permissions.
   *
   * While the class's access methods may be called repeatedly to
   * check for permission on each operation, this function consolidates
   * those calls and checks permissions all at once for all known operations.
   * The returned associative array has operation names as keys, and
   * TRUE/FALSE values that indicate if the operation is allowed.
   *
   * Operations include:
   * - 'chown'.
   * - 'create'.
   * - 'delete'.
   * - 'share'.
   * - 'update'.
   * - 'view'.
   *
   * The $entity argument names an entity for which access is checked.
   * If this is NULL, access checks are for operations on the root item
   * list for which there is no parent entity.
   *
   * @param \Drupal\foldershare\Entity\FolderShare $entity
   *   (optional, default = NULL = user root list) The entity for which
   *   access grants are checked.  If this is NULL, getRootAccessSummary()
   *   is called for FolderShareInterface::USER_ROOT_LIST.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   (optional, default = NULL = current user) The user for which to check
   *   access.
   *
   * @return boolean[]
   *   The returned associative array has operation names as keys, and
   *   TRUE/FALSE values that indicate if the user has permission for
   *   the associated operation.
   */
  public static function getAccessSummary(
    FolderShare $entity = NULL,
    AccountInterface $account = NULL) {
 
    if ($account === NULL) {
      $account = \Drupal::currentUser();
    }
 
    if ($entity === NULL) {
      if ($account->isAnonymous() === TRUE) {
        return self::getRootAccessSummary(
          FolderShareInterface::PUBLIC_ROOT_LIST,
          $account);
      }
 
      return self::getRootAccessSummary(
        FolderShareInterface::USER_ROOT_LIST,
        $account);
    }
 
    // Check if the user can perform a specific operation. This should be
    // read as "can the user OPERATOR the item?". For example,
    // "can the user DELETE the item?"
    //
    // The 'create' operator should be read as "can the user CREATE within
    // the item?".
    $a = [
      'chown'  => $entity->access('chown', $account, FALSE),
      'create' => $entity->access('create', $account, FALSE),
      'delete' => $entity->access('delete', $account, FALSE),
      'share'  => $entity->access('share', $account, FALSE),
      'update' => $entity->access('update', $account, FALSE),
      'view'   => $entity->access('view', $account, FALSE),
    ];
    return $a;
  }
 
  /**
   * Returns a list of rootlist operations and their permissions.
   *
   * While the class's access methods may be called repeatedly to
   * check for permission on each operation, this function consolidates
   * those calls and checks permissions all at once for all known operations.
   * The returned associative array has operation names as keys, and
   * TRUE/FALSE values that indicate if the operation is allowed.
   *
   * Operations include:
   * - 'chown'.
   * - 'create'.
   * - 'delete'.
   * - 'share'.
   * - 'update'.
   * - 'view'.
   *
   * The $rootId argument names a root list for which access is checked.
   *
   * @param int $rootId
   *   (optional, default = FolderShareInterface::USER_ROOT_LIST) The ID
   *   for a root list for which access grants are checked. Values are
   *   expected to be one of the well-known root lists:
   *   FolderShareInterface::USER_ROOT_LIST,
   *   FolderShareInterface::ALL_ROOT_LIST, or
   *   FolderShareInterface::PUBLIC_ROOT_LIST. All other values return
   *   no permissions.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   (optional, default = NULL = current user) The user for which to check
   *   access.
   *
   * @return boolean[]
   *   The returned associative array has operation names as keys, and
   *   TRUE/FALSE values that indicate if the user has permission for
   *   the associated operation.
   */
  public static function getRootAccessSummary(
    int $rootId = FolderShareInterface::USER_ROOT_LIST,
    AccountInterface $account = NULL) {
 
    //
    // Validate.
    // ---------
    // Get the account to check.
    if ($account === NULL) {
      $account = \Drupal::currentUser();
    }
 
    // Make sure the parent ID is for a root list.
    switch ($rootId) {
      case FolderShareInterface::ALL_ROOT_LIST:
        // Treat as the user's root list.
        if ($account->isAnonymous() === TRUE) {
          $rootId = FolderShareInterface::PUBLIC_ROOT_LIST;
        }
        else {
          $rootId = FolderShareInterface::USER_ROOT_LIST;
        }
        break;
 
      case FolderShareInterface::USER_ROOT_LIST:
      case FolderShareInterface::PUBLIC_ROOT_LIST:
        break;
 
      default:
        // For any other entity ID, no permissions.
        return [
          'chown'  => FALSE,
          'create' => FALSE,
          'delete' => FALSE,
          'share'  => FALSE,
          'update' => FALSE,
          'view'   => FALSE,
        ];
    }
 
    // Get entity info.
    $entityTypeManager = \Drupal::entityTypeManager();
    $accessController = $entityTypeManager->getAccessControlHandler(
      FolderShare::ENTITY_TYPE_ID);
 
    //
    // Allow site & content administrators everything.
    // -----------------------------------------------
    // Drupal insures that users marked as site administrators always have
    // all permissions. The check below, then, will always return TRUE for
    // site admins.
    //
    // Content administrators have this module's ADMINISTER_PERMISSION,
    // which grants them access to everything.
    if ($account->hasPermission(Constants::ADMINISTER_PERMISSION) === TRUE) {
      // The user is either a site admin or they have the module's
      // content admin permission.
      //
      // For the public root list, allow admins all access EXCEPT create.
      // It doesn't make sense to create within the public list if the user
      // is not anonymous. The created item would be owned by the current
      // admin user, not anonymous, so it would not show up in the public
      // root list being shown.
      //
      // There are three "right" ways to make things public:
      // - Create an item in a user's own root list, then share it with the
      //   public.
      // - Create an item as anonymous, assuming anonymous has author access.
      //   The created item will be owned by anonymous and show up in the
      //   public list.
      // - Create an item in a user's own root list, then an admin changes
      //   the item's ownership to anonymous. The item will move to the public
      //   list.
      //
      // It is feasible that a site has granted the anonymous user admin
      // permission, though that is a terrible idea. In that case, we're in
      // this block of code and the user is anonymous. Allow them create
      // access, but no other admin.
      if ($rootId === FolderShareInterface::PUBLIC_ROOT_LIST) {
        return [
          'chown'  => TRUE,
          'create' => ($account->isAnonymous()),
          'delete' => TRUE,
          'share'  => TRUE,
          'update' => TRUE,
          'view'   => TRUE,
        ];
      }
 
      // For any other root list, admins can do everything.
      return [
        'chown'  => TRUE,
        'create' => TRUE,
        'delete' => TRUE,
        'share'  => TRUE,
        'update' => TRUE,
        'view'   => TRUE,
      ];
    }
 
    //
    // Check permissions.
    // ------------------
    // Check if the user can perform a specific operation. This should be
    // read as "can the user OPERATOR items in the root list?". For example,
    // "can the user DELETE items in the root list?"
    //
    // The 'create' permission requires a special call back to the access
    // controller, while the others are based on permissions.
    //
    // From the earlier comments, note again that there are three "right"
    // ways to make things public:
    // - Create an item in a user's root list, then share with public.
    // - Create an item in a user's root list, then change ownership to
    //   anonymous.
    // - Create an item in the public root list directly as anonymous.
    //
    // It is not possible to create directly into the public root list unless
    // the user is anonymous. In that case, the public root list is their
    // home root list and they can create if they have permission.
    if ($rootId === FolderShareInterface::PUBLIC_ROOT_LIST) {
      if ($account->isAnonymous() === TRUE) {
        $canCreate = $accessController->createAccess(NULL, $account);
      }
      else {
        $canCreate = FALSE;
      }
    }
    else {
      $canCreate = $accessController->createAccess(NULL, $account);
    }
 
    $canView = $account->hasPermission(Constants::VIEW_PERMISSION);
 
    $canAuthor = $account->hasPermission(Constants::AUTHOR_PERMISSION);
 
    if ($account->isAnonymous() === TRUE) {
      $canShare = FALSE;
    }
    else {
      $canShare = $account->hasPermission(Constants::SHARE_PERMISSION) ||
        $account->hasPermission(Constants::SHARE_PUBLIC_PERMISSION);
    }
 
    return [
      // Non-administrators cannot change content ownership.
      'chown'  => FALSE,
 
      // Other operations depend upon the user's permissions.
      'create' => $canCreate,
      'delete' => $canAuthor,
      'share'  => $canShare,
      'update' => $canAuthor,
      'view'   => $canView,
    ];
  }
 
}

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

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