From bb91b33df84609af587a7673a9a5a8fe0b0e6cbe Mon Sep 17 00:00:00 2001
From: Dries <dries@buytaert.net>
Date: Thu, 24 Jan 2013 15:04:49 -0500
Subject: [PATCH] Issue #1862752 by larowlan, fago: Implement entity access API
 for users.

---
 core/includes/entity.inc                      | 15 ++++
 core/modules/openid/openid.module             |  8 +-
 core/modules/tracker/tracker.module           |  2 +-
 .../Drupal/user/Plugin/Core/Entity/User.php   |  1 +
 .../user/Plugin/views/field/LinkCancel.php    |  2 +-
 .../user/Plugin/views/field/LinkEdit.php      |  2 +-
 .../lib/Drupal/user/UserAccessController.php  | 74 +++++++++++++++++++
 core/modules/user/user.module                 | 59 ++-------------
 8 files changed, 105 insertions(+), 58 deletions(-)
 create mode 100644 core/modules/user/lib/Drupal/user/UserAccessController.php

diff --git a/core/includes/entity.inc b/core/includes/entity.inc
index 2d21e8222c7b..08ed91753046 100644
--- a/core/includes/entity.inc
+++ b/core/includes/entity.inc
@@ -734,3 +734,18 @@ function entity_get_render_display(EntityInterface $entity, $view_mode) {
 function entity_query($entity_type, $conjunction = 'AND') {
   return drupal_container()->get('entity.query')->get($entity_type, $conjunction);
 }
+
+/**
+ * Generic access callback for entity pages.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity for which access is being checked.
+ * @param string $operation
+ *   (optional) The operation being performed on the entity. Defaults to 'view'.
+ *
+ * @return bool
+ *   TRUE if the access is granted. FALSE if access is denied.
+ */
+function entity_page_access(EntityInterface $entity, $operation = 'view') {
+  return $entity->access($operation);
+}
diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module
index ca3d96853fca..6d31124b2bb1 100644
--- a/core/modules/openid/openid.module
+++ b/core/modules/openid/openid.module
@@ -27,8 +27,8 @@ function openid_menu() {
     'title' => 'OpenID identities',
     'page callback' => 'openid_user_identities',
     'page arguments' => array(1),
-    'access callback' => 'user_edit_access',
-    'access arguments' => array(1),
+    'access callback' => 'entity_page_access',
+    'access arguments' => array(1, 'update'),
     'type' => MENU_LOCAL_TASK,
     'file' => 'openid.pages.inc',
   );
@@ -36,8 +36,8 @@ function openid_menu() {
     'title' => 'Delete OpenID',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('openid_user_delete_form', 1),
-    'access callback' => 'user_edit_access',
-    'access arguments' => array(1),
+    'access callback' => 'entity_page_access',
+    'access arguments' => array(1, 'update'),
     'file' => 'openid.pages.inc',
   );
   return $items;
diff --git a/core/modules/tracker/tracker.module b/core/modules/tracker/tracker.module
index d33a878b2c2f..451702157af4 100644
--- a/core/modules/tracker/tracker.module
+++ b/core/modules/tracker/tracker.module
@@ -185,7 +185,7 @@ function _tracker_myrecent_access($account) {
  * @see tracker_menu()
  */
 function _tracker_user_access($account) {
-  return user_view_access($account) && user_access('access content');
+  return $account->access('view') && user_access('access content');
 }
 
 /**
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
index c4f2c92417ec..21e914debf84 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
@@ -19,6 +19,7 @@
  *   label = @Translation("User"),
  *   module = "user",
  *   controller_class = "Drupal\user\UserStorageController",
+ *   access_controller_class = "Drupal\user\UserAccessController",
  *   form_controller_class = {
  *     "profile" = "Drupal\user\ProfileFormController",
  *     "register" = "Drupal\user\RegisterFormController"
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/field/LinkCancel.php b/core/modules/user/lib/Drupal/user/Plugin/views/field/LinkCancel.php
index 51fb108c04f2..4d6cd274e3a7 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/field/LinkCancel.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/field/LinkCancel.php
@@ -26,7 +26,7 @@ class LinkCancel extends Link {
    * Overrides \Drupal\user\Plugin\views\field\Link::render_link().
    */
   public function render_link(EntityInterface $entity, \stdClass $values) {
-    if ($entity && user_cancel_access($entity)) {
+    if ($entity && $entity->access('delete')) {
       $this->options['alter']['make_link'] = TRUE;
 
       $text = !empty($this->options['text']) ? $this->options['text'] : t('cancel');
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/field/LinkEdit.php b/core/modules/user/lib/Drupal/user/Plugin/views/field/LinkEdit.php
index 27909e49b520..82931c9ec27e 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/field/LinkEdit.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/field/LinkEdit.php
@@ -26,7 +26,7 @@ class LinkEdit extends Link {
    * Overrides \Drupal\user\Plugin\views\field\Link::render_link().
    */
   public function render_link(EntityInterface $entity, \stdClass $values) {
-    if ($entity && user_edit_access($entity)) {
+    if ($entity && $entity->access('edit')) {
       $this->options['alter']['make_link'] = TRUE;
 
       $text = !empty($this->options['text']) ? $this->options['text'] : t('edit');
diff --git a/core/modules/user/lib/Drupal/user/UserAccessController.php b/core/modules/user/lib/Drupal/user/UserAccessController.php
new file mode 100644
index 000000000000..f0202d0d9c8b
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserAccessController.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\UserAccessController.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityAccessControllerInterface;
+use Drupal\user\Plugin\Core\Entity\User;
+
+/**
+ * Defines the access controller for the user entity type.
+ */
+class UserAccessController implements EntityAccessControllerInterface {
+
+  /**
+   * Implements EntityAccessControllerInterface::viewAccess().
+   */
+  public function viewAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    $uid = $entity->uid;
+    if (!$account) {
+      $account = $GLOBALS['user'];
+    }
+
+    // Never allow access to view the anonymous user account.
+    if ($uid) {
+      // Admins can view all, users can view own profiles at all times.
+      if ($account->uid == $uid || user_access('administer users', $account)) {
+        return TRUE;
+      }
+      elseif (user_access('access user profiles', $account)) {
+        // Only allow view access if the account is active.
+        return $entity->status;
+      }
+    }
+    return FALSE;
+  }
+
+  /**
+   * Implements EntityAccessControllerInterface::createAccess().
+   */
+  public function createAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    return user_access('administer users', $account);
+  }
+
+  /**
+   * Implements EntityAccessControllerInterface::updateAccess().
+   */
+  public function updateAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    if (!$account) {
+      $account = $GLOBALS['user'];
+    }
+    // Users can always edit their own account. Users with the 'administer
+    // users' permission can edit any account except the anonymous account.
+    return (($account->uid == $entity->uid) || user_access('administer users', $account)) && $entity->uid > 0;
+  }
+
+  /**
+   * Implements EntityAccessControllerInterface::deleteAccess().
+   */
+  public function deleteAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    if (!$account) {
+      $account = $GLOBALS['user'];
+    }
+    // Users with 'cancel account' permission can cancel their own account,
+    // users with 'administer users' permission can cancel any account except
+    // the anonymous account.
+    return ((($account->uid == $entity->uid) && user_access('cancel account', $account)) || user_access('administer users', $account)) && $entity->uid > 0;
+  }
+
+}
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 55314bbee144..4500c9beecfa 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -861,49 +861,6 @@ function user_register_access() {
   return user_is_anonymous() && (config('user.settings')->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY);
 }
 
-/**
- * User view access callback.
- *
- * @param $account
- *   Can either be a full user object or a $uid.
- */
-function user_view_access($account) {
-  $uid = is_object($account) ? $account->uid : (int) $account;
-
-  // Never allow access to view the anonymous user account.
-  if ($uid) {
-    // Admins can view all, users can view own profiles at all times.
-    if ($GLOBALS['user']->uid == $uid || user_access('administer users')) {
-      return TRUE;
-    }
-    elseif (user_access('access user profiles')) {
-      // At this point, load the complete account object.
-      if (!is_object($account)) {
-        $account = user_load($uid);
-      }
-      return (is_object($account) && $account->status);
-    }
-  }
-  return FALSE;
-}
-
-/**
- * Access callback for user account editing.
- */
-function user_edit_access($account) {
-  return (($GLOBALS['user']->uid == $account->uid) || user_access('administer users')) && $account->uid > 0;
-}
-
-/**
- * Menu access callback; limit access to account cancellation pages.
- *
- * Limit access to users with the 'cancel account' permission or administrative
- * users, and prevent the anonymous user from cancelling the account.
- */
-function user_cancel_access($account) {
-  return ((($GLOBALS['user']->uid == $account->uid) && user_access('cancel account')) || user_access('administer users')) && $account->uid > 0;
-}
-
 /**
  * Implements hook_menu().
  */
@@ -1079,7 +1036,7 @@ function user_menu() {
     'title arguments' => array(1),
     'page callback' => 'user_view_page',
     'page arguments' => array(1),
-    'access callback' => 'user_view_access',
+    'access callback' => 'entity_page_access',
     'access arguments' => array(1),
   );
 
@@ -1093,8 +1050,8 @@ function user_menu() {
     'title' => 'Cancel account',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('user_cancel_confirm_form', 1),
-    'access callback' => 'user_cancel_access',
-    'access arguments' => array(1),
+    'access callback' => 'entity_page_access',
+    'access arguments' => array(1, 'delete'),
     'file' => 'user.pages.inc',
   );
 
@@ -1102,8 +1059,8 @@ function user_menu() {
     'title' => 'Confirm account cancellation',
     'page callback' => 'user_cancel_confirm',
     'page arguments' => array(1, 4, 5),
-    'access callback' => 'user_cancel_access',
-    'access arguments' => array(1),
+    'access callback' => 'entity_page_access',
+    'access arguments' => array(1, 'delete'),
     'file' => 'user.pages.inc',
   );
 
@@ -1111,8 +1068,8 @@ function user_menu() {
     'title' => 'Edit',
     'page callback' => 'entity_get_form',
     'page arguments' => array(1, 'profile'),
-    'access callback' => 'user_edit_access',
-    'access arguments' => array(1),
+    'access callback' => 'entity_page_access',
+    'access arguments' => array(1, 'update'),
     'type' => MENU_LOCAL_TASK,
     'file' => 'user.pages.inc',
   );
@@ -2715,7 +2672,7 @@ function user_rdf_mapping() {
  */
 function user_file_download_access($field, EntityInterface $entity, File $file) {
   if ($entity->entityType() == 'user') {
-    return user_view_access($entity);
+    return $entity->access('view');
   }
 }
 
-- 
GitLab