Skip to content

Commit

Permalink
Fixes backdrop#3011: Added entity_access and Entity::createAccess() a…
Browse files Browse the repository at this point in the history
…nd Entity::access() for all Entities.
  • Loading branch information
moonray committed Apr 4, 2018
1 parent 3e9f571 commit 62c90f7
Show file tree
Hide file tree
Showing 16 changed files with 642 additions and 191 deletions.
84 changes: 84 additions & 0 deletions core/modules/comment/comment.entity.inc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ class Comment extends Entity {
*/
public $homepage;

/**
* Cached access values.
*
* @var array
*
* @see Node::access()
*/
private $rights = array();

/**
* Implements EntityInterface::id().
*/
Expand Down Expand Up @@ -117,6 +126,81 @@ class Comment extends Entity {
'options' => array('fragment' => 'comment-' . $this->cid),
);
}

/**
* Overrides Entity::createAccess().
*/
public static function createAccess($account = NULL) {
$rights = &backdrop_static(__METHOD__, []);

// If no user object is supplied, the access check is for the current user.
if (empty($account)) {
$account = $GLOBALS['user'];
}

// If we've already checked access for this node, user and op, return from
// cache.
if (isset($rights[$account->uid])) {
return $rights[$account->uid];
}

$rights[$account->uid] = user_access('post comments', $account);
return $rights[$account->uid];
}

/**
* Overrides Entity::access().
*
* @param string $op
* The operation to be performed on the node. Possible values are:
* - "view".
* - "update".
* - "approve".
* - "delete".
* - "delete".
* @param User|AnonymousUser $account
* (optional) The user to check for. Leave it to NULL to check for the
* global user.
*
* @return bool
* TRUE if access is granted, FALSE otherwise.
*/
public function access($op, $account = NULL) {
if (!in_array($op, array('view', 'update', 'apprive', 'delete'), TRUE)) {
// If the $op was not one of the supported ones, we return access denied.
return FALSE;
}
// If no user object is supplied, the access check is for the current user.
if (empty($account)) {
$account = $GLOBALS['user'];
}

// If we've already checked access for this node, user and op, return from
// cache.
if (isset($this->rights[$account->uid][$op])) {
return $this->rights[$account->uid][$op];
}

if ($op == 'view') {
$this->rights[$account->uid][$op] = user_access('access comments', $account);
return $this->rights[$account->uid][$op];
}
elseif ($op == 'update') {
$this->rights[$account->uid][$op] = ($account->uid && $account->uid == $this->uid && $this->status == COMMENT_PUBLISHED && user_access('edit own comments', $account)) || user_access('administer comments', $account);
return $this->rights[$account->uid][$op];
}
elseif ($op == 'approve') {
$this->rights[$account->uid][$op] = user_access('administer comments', $account);
return $this->rights[$account->uid][$op];
}
elseif ($op == 'delete') {
$this->rights[$account->uid][$op] = user_access('administer comments', $account);
return $this->rights[$account->uid][$op];
}

return FALSE;
}

}

/**
Expand Down
76 changes: 32 additions & 44 deletions core/modules/comment/comment.module
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ function comment_node_view(Node $node, $view_mode) {
}
if ($node->comment == COMMENT_NODE_OPEN) {
$comment_form_location = $node_type->settings['comment_form_location'];
if (user_access('post comments')) {
if (Comment::createAccess()) {
$links['comment-add'] = array(
'title' => t('Add comment'),
'href' => "node/$node->nid",
Expand All @@ -663,7 +663,7 @@ function comment_node_view(Node $node, $view_mode) {
// indexing or constructing a search result excerpt.
if ($node->comment == COMMENT_NODE_OPEN) {
$comment_form_location = $node_type->settings['comment_form_location'];
if (user_access('post comments')) {
if (Comment::createAccess()) {
// Show the "post comment" link if the form is on another page, or
// if there are existing comments that the link will skip past.
if ($comment_form_location == COMMENT_FORM_SEPARATE_PAGE || (!empty($node->comment_count) && user_access('access comments'))) {
Expand Down Expand Up @@ -737,7 +737,7 @@ function comment_node_page_additions(Node $node) {
}

// Append comment form if needed.
if (user_access('post comments') && $node->comment == COMMENT_NODE_OPEN && ($node_type->settings['comment_form_location'] == COMMENT_FORM_BELOW)) {
if (Comment::createAccess() && $node->comment == COMMENT_NODE_OPEN && ($node_type->settings['comment_form_location'] == COMMENT_FORM_BELOW)) {
$comment = entity_create('comment', array('nid' => $node->nid));
$additions['comment_form'] = backdrop_get_form("comment_node_{$node->type}_form", $comment);
}
Expand Down Expand Up @@ -1032,23 +1032,29 @@ function comment_build_content(Comment $comment, Node $node, $view_mode = 'full'
function comment_links(Comment $comment, Node $node) {
$links = array();
if ($node->comment == COMMENT_NODE_OPEN) {
if (user_access('administer comments') && user_access('post comments')) {
$links['comment-delete'] = array(
'title' => t('delete'),
'href' => "comment/$comment->cid/delete",
'html' => TRUE,
);
$links['comment-edit'] = array(
'title' => t('edit'),
'href' => "comment/$comment->cid/edit",
'html' => TRUE,
);
$links['comment-reply'] = array(
'title' => t('reply'),
'href' => "comment/reply/$comment->nid/$comment->cid",
'html' => TRUE,
);
if ($comment->status == COMMENT_NOT_PUBLISHED) {
if ($comment->access('delete') || $comment->access('edit') || Comment::createAccess() || $comment->access('approve')) {
if ($comment->access('delete')) {
$links['comment-delete'] = [
'title' => t('delete'),
'href' => "comment/$comment->cid/delete",
'html' => TRUE,
];
}
if ($comment->access('edit')) {
$links['comment-edit'] = [
'title' => t('edit'),
'href' => "comment/$comment->cid/edit",
'html' => TRUE,
];
}
if (Comment::createAccess()) {
$links['comment-reply'] = [
'title' => t('reply'),
'href' => "comment/reply/$comment->nid/$comment->cid",
'html' => TRUE,
];
}
if ($comment->status == COMMENT_NOT_PUBLISHED && $comment->access('approve')) {
$links['comment-approve'] = array(
'title' => t('approve'),
'href' => "comment/$comment->cid/approve",
Expand All @@ -1057,20 +1063,6 @@ function comment_links(Comment $comment, Node $node) {
);
}
}
elseif (user_access('post comments')) {
if (comment_access('edit', $comment)) {
$links['comment-edit'] = array(
'title' => t('edit'),
'href' => "comment/$comment->cid/edit",
'html' => TRUE,
);
}
$links['comment-reply'] = array(
'title' => t('reply'),
'href' => "comment/reply/$comment->nid/$comment->cid",
'html' => TRUE,
);
}
else {
$links['comment-forbidden']['title'] = theme('comment_post_forbidden', array('node' => $node));
$links['comment-forbidden']['html'] = TRUE;
Expand Down Expand Up @@ -1479,21 +1471,17 @@ function comment_config_create_validate(Config $staging_config, $all_changes) {
* replied to. This prevents people from changing or revising their statements
* based on the replies to their posts.
*
* @param $op
* @param string $op
* The operation that is to be performed on the comment. Only 'edit' is
* recognized now.
* @param $comment
* @param Comment $comment
* The comment object.
*
* @return
* @return bool
* TRUE if the current user has acces to the comment, FALSE otherwise.
*/
function comment_access($op, $comment) {
global $user;

if ($op == 'edit') {
return ($user->uid && $user->uid == $comment->uid && $comment->status == COMMENT_PUBLISHED && user_access('edit own comments')) || user_access('administer comments');
}
function comment_access($op, Comment $comment) {
return $comment->access($op);
}

/**
Expand Down Expand Up @@ -2122,7 +2110,7 @@ function comment_form_submit_build_comment($form, &$form_state) {
function comment_form_submit($form, &$form_state) {
$node = node_load($form_state['values']['nid']);
$comment = comment_form_submit_build_comment($form, $form_state);
if (user_access('post comments') && (user_access('administer comments') || $node->comment == COMMENT_NODE_OPEN)) {
if (Comment::createAccess() && (user_access('administer comments') || $node->comment == COMMENT_NODE_OPEN)) {
// Save the anonymous user information to a cookie for reuse.
if (user_is_anonymous()) {
user_cookie_save(array_intersect_key($form_state['values'], array_flip(array('name', 'mail', 'homepage'))));
Expand Down
31 changes: 30 additions & 1 deletion core/modules/entity/entity.class.inc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ interface EntityInterface {
* @return
* The type of the entity.
*/
public function entityType();
public static function entityType();

/**
* Returns the bundle of the entity.
Expand Down Expand Up @@ -74,6 +74,35 @@ interface EntityInterface {
*/
public function uri();

/**
* Determines whether the given user has access to create this type of entity.
*
* @param User|AnonymousUser $account
* (optional) The user to check for. Leave it to NULL to check for the
* global user.
*
* @return bool
* Whether access is allowed or not. If the entity type does not specify any
* access information, NULL is returned.
*/
public static function createAccess($account = NULL);

/**
* Determines whether the given user has access to this entity.
*
* @param string $op
* The operation being performed. One of 'view', 'update', 'create' or
* 'delete'.
* @param User|AnonymousUser $account
* (optional) The user to check for. Leave it to NULL to check for the
* global user.
*
* @return bool
* Whether access is allowed or not. If the entity type does not specify any
* access information, NULL is returned.
*/
public function access($op, $account = NULL);

/**
* Saves an entity permanently.
*
Expand Down
26 changes: 26 additions & 0 deletions core/modules/entity/entity.module
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,32 @@ function entity_view_mode_exists($machine_name, $element, $form_state) {
return !empty($entity_info['view modes'][$machine_name]);
}

/**
* Determines whether the given user has access to an entity.
*
* @param string $op
* The operation being performed. One of 'view', 'update', 'create' or
* 'delete'.
* @param string $entity_type
* The entity type of the entity to check for.
* @param EntityInterface $entity
* Optionally an entity to check access for. If no entity is given, it will be
* determined whether access is allowed for all entities of the given type.
* @param User $account
* The user to check for. Leave it to NULL to check for the global user.
*
* @return bool
* Whether access is allowed or not. If the entity type does not specify any
* access information, NULL is returned.
*
* @see entity_type_supports()
*/
function entity_access($op, $entity_type, EntityInterface $entity = NULL, User $account = NULL) {
if (($info = entity_get_info()) && isset($info[$entity_type]['access callback'])) {
return $info[$entity_type]['access callback']($op, $entity, $account, $entity_type);
}
}

/**
* Gets the entity info array of an entity type.
*
Expand Down
36 changes: 32 additions & 4 deletions core/modules/entity/tests/entity_test/entity_test.entity.inc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* @file
* Test entity classes.
Expand All @@ -10,21 +11,48 @@
class TestEntity extends Entity {
public $id;

function id() {
/**
* Implements EntityInterface::id().
*/
public function id() {
return $this->id;
}

public function entityType() {
/**
* Implements EntityInterface::entityType().
*/
public static function entityType() {
return 'entity_test';
}

function label() {
/**
* Implements EntityInterface::label().
*/
public function label() {
return 'label';
}

function uri() {
/**
* Implements EntityInterface::uri().
*/
public function uri() {
return array(
'path' => 'test/' . $this->id,
);
}

/**
* Implements EntityInterface::createAccess().
*/
public static function createAccess($account = NULL) {
return TRUE;
}

/**
* Implements EntityInterface::access().
*/
public function access($op, $account = NULL) {
return TRUE;
}

}
Loading

0 comments on commit 62c90f7

Please sign in to comment.