Unverified Commit 57fe6127 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2348203 by agentrickard, govind.maloo, mohit_aghera, dagmar, init90,...

Issue #2348203 by agentrickard, govind.maloo, mohit_aghera, dagmar, init90, Berdir, alexpott, chx, catch, xjm: hook_node_access() no longer fires for the 'create' operation

(cherry picked from commit aa8d81c7)
parent 20f191f3
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -616,6 +616,18 @@
 * are invoked are hook_entity_create_access() and
 * hook_ENTITY_TYPE_create_access() instead.
 *
 * The access to an entity can be influenced in several ways:
 * - To explicitly allow access, return an AccessResultInterface object with
 * isAllowed() returning TRUE. Other modules can override this access by
 * returning TRUE for isForbidden().
 * - To explicitly forbid access, return an AccessResultInterface object with
 * isForbidden() returning TRUE. Access will be forbidden even if your module
 * (or another module) also returns TRUE for isNeutral() or isAllowed().
 * - To neither allow nor explicitly forbid access, return an
 * AccessResultInterface object with isNeutral() returning TRUE.
 * - If your module does not return an AccessResultInterface object, neutral
 * access will be assumed.
 *
 * The Node entity type has a complex system for determining access, which
 * developers can interact with. This is described in the
 * @link node_access Node access topic. @endlink
@@ -643,7 +655,10 @@
 * @param string $operation
 *   The operation that is to be performed on $entity.
 * @param \Drupal\Core\Session\AccountInterface $account
 *   The account trying to access the entity.
 *   The account trying to access the entity. Usually one of:
 *   - "view"
 *   - "update"
 *   - "delete"
 *
 * @return \Drupal\Core\Access\AccessResultInterface
 *   The access result. The final result is calculated by using
@@ -677,7 +692,10 @@ function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operat
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity to check access to.
 * @param string $operation
 *   The operation that is to be performed on $entity.
 *   The operation that is to be performed on $entity. Usually one of:
 *   - "view"
 *   - "update"
 *   - "delete"
 * @param \Drupal\Core\Session\AccountInterface $account
 *   The account trying to access the entity.
 *
+0 −74
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@
use Drupal\node\NodeInterface;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Access\AccessResult;

/**
 * @addtogroup hooks
@@ -286,79 +285,6 @@ function hook_node_grants_alter(&$grants, \Drupal\Core\Session\AccountInterface
  }
}

/**
 * Controls access to a node.
 *
 * Modules may implement this hook if they want to have a say in whether or not
 * a given user has access to perform a given operation on a node.
 *
 * The administrative account (user ID #1) always passes any access check, so
 * this hook is not called in that case. Users with the "bypass node access"
 * permission may always view and edit content through the administrative
 * interface.
 *
 * The access to a node can be influenced in several ways:
 * - To explicitly allow access, return an AccessResultInterface object with
 * isAllowed() returning TRUE. Other modules can override this access by
 * returning TRUE for isForbidden().
 * - To explicitly forbid access, return an AccessResultInterface object with
 * isForbidden() returning TRUE. Access will be forbidden even if your module
 * (or another module) also returns TRUE for isNeutral() or isAllowed().
 * - To neither allow nor explicitly forbid access, return an
 * AccessResultInterface object with isNeutral() returning TRUE.
 * - If your module does not return an AccessResultInterface object, neutral
 * access will be assumed.
 *
 * Also note that this function isn't called for node listings (e.g., RSS feeds,
 * the default home page at path 'node', a recent content block, etc.) See
 * @link node_access Node access rights @endlink for a full explanation.
 *
 * @param \Drupal\node\NodeInterface|string $node
 *   Either a node entity or the machine name of the content type on which to
 *   perform the access check.
 * @param string $op
 *   The operation to be performed. Possible values:
 *   - "create"
 *   - "delete"
 *   - "update"
 *   - "view"
 * @param \Drupal\Core\Session\AccountInterface $account
 *   The user object to perform the access check operation on.
 *
 * @return \Drupal\Core\Access\AccessResultInterface
 *   The access result.
 *
 * @ingroup node_access
 */
function hook_node_access(\Drupal\node\NodeInterface $node, $op, \Drupal\Core\Session\AccountInterface $account) {
  $type = $node->bundle();

  switch ($op) {
    case 'create':
      return AccessResult::allowedIfHasPermission($account, 'create ' . $type . ' content');

    case 'update':
      if ($account->hasPermission('edit any ' . $type . ' content')) {
        return AccessResult::allowed()->cachePerPermissions();
      }
      else {
        return AccessResult::allowedIf($account->hasPermission('edit own ' . $type . ' content') && ($account->id() == $node->getOwnerId()))->cachePerPermissions()->cachePerUser()->addCacheableDependency($node);
      }

    case 'delete':
      if ($account->hasPermission('delete any ' . $type . ' content')) {
        return AccessResult::allowed()->cachePerPermissions();
      }
      else {
        return AccessResult::allowedIf($account->hasPermission('delete own ' . $type . ' content') && ($account->id() == $node->getOwnerId()))->cachePerPermissions()->cachePerUser()->addCacheableDependency($node);
      }

    default:
      // No opinion.
      return AccessResult::neutral();
  }
}

/**
 * Act on a node being displayed as a search result.
 *
+31 −26
Original line number Diff line number Diff line
@@ -950,16 +950,16 @@ function node_form_system_themes_admin_form_submit($form, FormStateInterface $fo
 * @{
 * The node access system determines who can do what to which nodes.
 *
 * In determining access rights for a node, \Drupal\node\NodeAccessControlHandler
 * first checks whether the user has the "bypass node access" permission. Such
 * users have unrestricted access to all nodes. user 1 will always pass this
 * check.
 * In determining access rights for an existing node,
 * \Drupal\node\NodeAccessControlHandler first checks whether the user has the
 * "bypass node access" permission. Such users have unrestricted access to all
 * nodes. user 1 will always pass this check.
 *
 * Next, all implementations of hook_node_access() will be called. Each
 * implementation may explicitly allow, explicitly forbid, or ignore the access
 * request. If at least one module says to forbid the request, it will be
 * rejected. If no modules deny the request and at least one says to allow it,
 * the request will be permitted.
 * Next, all implementations of hook_ENTITY_TYPE_access() for node will
 * be called. Each implementation may explicitly allow, explicitly forbid, or
 * ignore the access request. If at least one module says to forbid the request,
 * it will be rejected. If no modules deny the request and at least one says to
 * allow it, the request will be permitted.
 *
 * If all modules ignore the access request, then the node_access table is used
 * to determine access. All node access modules are queried using
@@ -972,40 +972,42 @@ function node_form_system_themes_admin_form_submit($form, FormStateInterface $fo
 *
 * In node listings (lists of nodes generated from a select query, such as the
 * default home page at path 'node', an RSS feed, a recent content block, etc.),
 * the process above is followed except that hook_node_access() is not called on
 * each node for performance reasons and for proper functioning of the pager
 * system. When adding a node listing to your module, be sure to use an entity
 * query, which will add a tag of "node_access". This will allow modules dealing
 * with node access to ensure only nodes to which the user has access are
 * retrieved, through the use of hook_query_TAG_alter(). See the
 * the process above is followed except that hook_ENTITY_TYPE_access() is not
 * called on each node for performance reasons and for proper functioning of
 * the pager system. When adding a node listing to your module, be sure to use
 * an entity query, which will add a tag of "node_access". This will allow
 * modules dealing with node access to ensure only nodes to which the user has
 * access are retrieved, through the use of hook_query_TAG_alter(). See the
 * @link entity_api Entity API topic @endlink for more information on entity
 * queries. Tagging a query with "node_access" does not check the
 * published/unpublished status of nodes, so the base query is responsible
 * for ensuring that unpublished nodes are not displayed to inappropriate users.
 *
 * Note: Even a single module returning an AccessResultInterface object from
 * hook_node_access() whose isForbidden() method equals TRUE will block access
 * to the node. Therefore, implementers should take care to not deny access
 * unless they really intend to. Unless a module wishes to actively forbid
 * access it should return an AccessResultInterface object whose isAllowed() nor
 * isForbidden() methods return TRUE, to allow other modules or the node_access
 * table to control access.
 * hook_ENTITY_TYPE_access() whose isForbidden() method equals TRUE will block
 * access to the node. Therefore, implementers should take care to not deny
 * access unless they really intend to. Unless a module wishes to actively
 * forbid access it should return an AccessResultInterface object whose
 * isAllowed() nor isForbidden() methods return TRUE, to allow other modules or
 * the node_access table to control access.
 *
 * Note also that access to create nodes is handled by
 * hook_ENTITY_TYPE_create_access().
 *
 * To see how to write a node access module of your own, see
 * node_access_example.module.
 *
 * @see \Drupal\node\NodeAccessControlHandler
 */

/**
 * Implements hook_node_access().
 * Implements hook_ENTITY_TYPE_access().
 */
function node_node_access(NodeInterface $node, $op, AccountInterface $account) {
  $type = $node->bundle();
  $access = AccessResult::neutral();

  // Note create access is handled by hook_ENTITY_TYPE_create_access().
  switch ($op) {
    case 'create':
      $access = AccessResult::allowedIfHasPermission($account, 'create ' . $type . ' content');

    case 'update':
      $access = AccessResult::allowedIfHasPermission($account, 'edit any ' . $type . ' content');
      if (!$access->isAllowed() && $account->hasPermission('edit own ' . $type . ' content')) {
@@ -1019,6 +1021,9 @@ function node_node_access(NodeInterface $node, $op, AccountInterface $account) {
        $access = $access->orIf(AccessResult::allowedIf($account->id() == $node->getOwnerId()))->cachePerUser()->addCacheableDependency($node);
      }
      break;

    default:
      $access = AccessResult::neutral();
  }

  return $access;