Commit c5f683b2 authored by Dries's avatar Dries

- Patch #537862 by Crell, Amitaibu, salvis: simplify and make more flexible...

- Patch #537862 by Crell, Amitaibu, salvis: simplify and make more flexible the node access by converting hook_access() to hook_node_access().
parent 425a1f95
......@@ -19,28 +19,6 @@ function blog_node_info() {
);
}
/**
* Implement hook_permission().
*/
function blog_permission() {
return node_list_permissions('blog');
}
/**
* Implement hook_access().
*/
function blog_access($op, $node, $account) {
switch ($op) {
case 'create':
// Anonymous users cannot post even if they have the permission.
return user_access('create blog content', $account) && $account->uid;
case 'update':
return user_access('edit any blog content', $account) || (user_access('edit own blog content', $account) && ($node->uid == $account->uid));
case 'delete':
return user_access('delete any blog content', $account) || (user_access('delete own blog content', $account) && ($node->uid == $account->uid));
}
}
/**
* Implement hook_user_view().
*/
......
......@@ -404,20 +404,6 @@ function forum_node_info() {
);
}
/**
* Implement hook_access().
*/
function forum_access($op, $node, $account) {
switch ($op) {
case 'create':
return user_access('create forum content', $account);
case 'update':
return user_access('edit any forum content', $account) || (user_access('edit own forum content', $account) && ($account->uid == $node->uid));
case 'delete':
return user_access('delete any forum content', $account) || (user_access('delete own forum content', $account) && ($account->uid == $node->uid));
}
}
/**
* Implement hook_permission().
*/
......@@ -428,7 +414,6 @@ function forum_permission() {
'description' => t('Manage forums and configure forum administration settings.'),
),
);
$perms += node_list_permissions('forum');
return $perms;
}
......
......@@ -341,6 +341,67 @@ function hook_node_load($nodes, $types) {
}
}
/**
* Control 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.
*
* Note that not all modules will want to influence access on all
* node types. If your module does not want to actively grant or
* block access, return NODE_ACCESS_IGNORE or simply return nothing.
* Blindly returning FALSE will break other node access modules.
*
* @link http://api.drupal.org/api/group/node_access/7 More on the node access system @endlink
* @ingroup node_access
* @param $node
* The node on which the operation is to be performed, or, if it does
* not yet exist, the type of node to be created.
* @param $op
* The operation to be performed. Possible values:
* - "create"
* - "delete"
* - "update"
* - "view"
* @param $account
* A user object representing the user for whom the operation is to be
* performed.
* @return
* NODE_ACCESS_ALLOW if the operation is to be allowed;
* NODE_ACCESS_DENY if the operation is to be denied;
* NODE_ACCESSS_IGNORE to not affect this operation at all.
*/
function hook_node_access($node, $op, $account) {
$type = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);
if (in_array($type, nodeperms_get_configured_types())) {
if ($op == 'create' && user_access('create ' . $type . ' content', $account)) {
return NODE_ACCESS_ALLOW;
}
if ($op == 'update') {
if (user_access('edit any ' . $type . ' content', $account) || (user_access('edit own ' . $type . ' content', $account) && ($account->uid == $node->uid))) {
return NODE_ACCESS_ALLOW;
}
}
if ($op == 'delete') {
if (user_access('delete any ' . $type . ' content', $account) || (user_access('delete own ' . $type . ' content', $account) && ($account->uid == $node->uid))) {
return NODE_ACCESS_ALLOW;
}
}
}
// Returning nothing from this function would have the same effect.
return NODE_ACCESS_IGNORE;
}
/**
* The node is about to be shown on the add/edit form.
*
......@@ -664,54 +725,6 @@ function hook_node_type_delete($info) {
variable_del('comment_' . $info->type);
}
/**
* Define access restrictions.
*
* This hook allows node modules to limit access to the node types they
* define.
*
* @param $op
* The operation to be performed. Possible values:
* - "create"
* - "delete"
* - "update"
* - "view"
* @param $node
* The node on which the operation is to be performed, or, if it does
* not yet exist, the type of node to be created.
* @param $account
* A user object representing the user for whom the operation is to be
* performed.
* @return
* TRUE if the operation is to be allowed;
* FALSE if the operation is to be denied;
* NULL to not override the settings in the node_access table, or access
* control modules.
*
* The administrative account (user ID #1) always passes any access check,
* so this hook is not called in that case. If this hook is not defined for
* a node type, all access checks will fail, so only the administrator will
* be able to see content of that type. However, users with the "administer
* nodes" permission may always view and edit content through the
* administrative interface.
* @see http://api.drupal.org/api/group/node_access/7
*
* For a detailed usage example, see node_example.module.
*
* @ingroup node_access
*/
function hook_access($op, $node, $account) {
if ($op == 'create') {
return user_access('create stories', $account);
}
if ($op == 'update' || $op == 'delete') {
if (user_access('edit own stories', $account) && ($account->uid == $node->uid)) {
return TRUE;
}
}
}
/**
* Respond to node deletion.
*
......@@ -929,11 +942,11 @@ function hook_validate($node, &$form) {
* @return
* $node. The passed $node parameter should be modified as necessary and
* returned so it can be properly presented. Nodes are prepared for display
* by assembling a structured array, formatted as in the Form API, in
* $node->content. As with Form API arrays, the #weight property can be
* by assembling a structured array, formatted as in the Form API, in
* $node->content. As with Form API arrays, the #weight property can be
* used to control the relative positions of added elements. After this
* hook is invoked, node_build() calls field_attach_view() to add field
* views to $node->content, and then invokes hook_node_view() and
* views to $node->content, and then invokes hook_node_view() and
* hook_node_build_alter(), so if you want to affect the final
* view of the node, you might consider implementing one of these hooks
* instead.
......
......@@ -15,6 +15,21 @@
*/
define('NODE_NEW_LIMIT', REQUEST_TIME - 30 * 24 * 60 * 60);
/**
* Modules should return this value from hook_node_access() to allow access to a node.
*/
define('NODE_ACCESS_ALLOW', 'allow');
/**
* Modules should return this value from hook_node_access() to deny access to a node.
*/
define('NODE_ACCESS_DENY', 'deny');
/**
* Modules should return this value from hook_node_access() to not affect node access.
*/
define('NODE_ACCESS_IGNORE', NULL);
/**
* Implement hook_help().
*/
......@@ -1337,10 +1352,9 @@ function node_permission() {
),
);
foreach (node_type_get_types() as $type) {
if ($type->base == 'node_content') {
$perms += node_list_permissions($type);
}
// Generate standard node permissions for all applicable node types.
foreach (node_permissions_get_configured_types() as $type) {
$perms += node_list_permissions($type);
}
return $perms;
......@@ -2222,27 +2236,35 @@ function node_search_validate($form, &$form_state) {
*
* In determining access rights for a node, node_access() first checks
* whether the user has the "bypass node access" permission. Such users have
* unrestricted access to all nodes. Then the node module's hook_access()
* is called, and a TRUE or FALSE return value will grant or deny access.
* This allows, for example, the blog module to always grant access to the
* blog author, and for the book module to always deny editing access to
* PHP pages.
*
* If node module does not intervene (returns NULL), then the
* node_access table is used to determine access. All node access
* modules are queried using hook_node_grants() to assemble a list of
* "grant IDs" for the user. This list is compared against the table.
* If any row contains the node ID in question (or 0, which stands for "all
* nodes"), one of the grant IDs returned, and a value of TRUE for the
* operation in question, then access is granted. Note that this table is a
* list of grants; any matching row is sufficient to grant access to the
* node.
* 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 deny, or ignore the access
* request. If at least one module says to deny 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
* hook_node_grants() to assemble a list of "grant IDs" for the user. This list
* is compared against the table. If any row contains the node ID in question
* (or 0, which stands for "all nodes"), one of the grant IDs returned, and a
* value of TRUE for the operation in question, then access is granted. Note
* that this table is a list of grants; any matching row is sufficient to
* grant access to the node.
*
* In node listings, the process above is followed except that
* hook_access() is not called on each node for performance reasons and for
* 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 db_rewrite_sql() to add
* the appropriate clauses to your query for access checks.
* module, be sure to use a dynamic query created by db_select() and add a tag
* of "node_access" to ensure that only nodes to which the user has access
* are retrieved.
*
* Note: Even a single module returning NODE_ACCESS_DENY from hook_node_access()
* 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 deny access it should return NODE_ACCESS_IGNORE (or simply return
* nothing) to allow other modules or the node_access table to control access.
*
* To see how to write a node access module of your own, see
* node_access_example.module.
......@@ -2292,12 +2314,17 @@ function node_access($op, $node, $account = NULL) {
return FALSE;
}
// Can't use node_invoke('access', $node), because the access hook takes the
// $op parameter before the $node parameter.
$base = node_type_get_base($node);
$access = module_invoke($base, 'access', $op, $node, $account);
if (!is_null($access)) {
return $access;
// We grant access to the node if both of the following conditions are met:
// - No modules say to deny access.
// - At least one module says to grant access.
// If no module specified either allow or deny, we fall back to the
// node_access table.
$access = module_invoke_all('node_access', $node, $op, $account);
if (in_array(NODE_ACCESS_DENY, $access, TRUE)) {
return FALSE;
}
elseif (in_array(NODE_ACCESS_ALLOW, $access, TRUE)) {
return TRUE;
}
// Check if authors can view their own unpublished nodes.
......@@ -2337,6 +2364,99 @@ function node_access($op, $node, $account = NULL) {
return FALSE;
}
/**
* Implement hook_node_access().
*/
function node_node_access($node, $op, $account) {
$type = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);
if (in_array($type, node_permissions_get_configured_types())) {
if ($op == 'create' && user_access('create ' . $type . ' content', $account)) {
return NODE_ACCESS_ALLOW;
}
if ($op == 'update') {
if (user_access('edit any ' . $type . ' content', $account) || (user_access('edit own ' . $type . ' content', $account) && ($account->uid == $node->uid))) {
return NODE_ACCESS_ALLOW;
}
}
if ($op == 'delete') {
if (user_access('delete any ' . $type . ' content', $account) || (user_access('delete own ' . $type . ' content', $account) && ($account->uid == $node->uid))) {
return NODE_ACCESS_ALLOW;
}
}
}
return NODE_ACCESS_IGNORE;
}
/**
* Helper function to generate standard node permission list for a given type.
*
* @param $type
* The machine-readable name of the node type.
* @return array
* An array of permission names and descriptions.
*/
function node_list_permissions($type) {
$info = node_type_get_type($type);
$type = check_plain($info->type);
// Build standard list of node permissions for this type.
$perms = array(
"create $type content" => array(
'title' => t('Create %type_name content', array('%type_name' => $info->name)),
'description' => t('Create new %type_name content.', array('%type_name' => $info->name)),
),
"edit own $type content" => array(
'title' => t('Edit own %type_name content', array('%type_name' => $info->name)),
'description' => t('Edit %type_name content created by the user.', array('%type_name' => $info->name)),
),
"edit any $type content" => array(
'title' => t('Edit any %type_name content', array('%type_name' => $info->name)),
'description' => t('Edit any %type_name content, regardless of its author.', array('%type_name' => $info->name)),
),
"delete own $type content" => array(
'title' => t('Delete own %type_name content', array('%type_name' => $info->name)),
'description' => t('Delete %type_name content created by the user.', array('%type_name' => $info->name)),
),
"delete any $type content" => array(
'title' => t('Delete any %type_name content', array('%type_name' => $info->name)),
'description' => t('Delete any %type_name content, regardless of its author.', array('%type_name' => $info->name)),
),
);
return $perms;
}
/**
* Returns an array of node types that should be managed by permissions.
*
* By default, this will include all node types in the system. To exclude a
* specific node from getting permissions defined for it, set the
* node_permissions_$type variable to 0. Core does not provide an interface
* for doing so, however, contrib modules may exclude their own nodes in
* hook_install(). Alternatively, contrib modules may configure all node types
* at once, or decide to apply some other hook_node_access() implementation
* to some or all node types.
*
* @return
* An array of node types managed by this module.
*/
function node_permissions_get_configured_types() {
$configured_types = array();
foreach (node_type_get_types() as $type => $info) {
if (variable_get('node_permissions_' . $type, 1)) {
$configured_types[] = $type;
}
}
return $configured_types;
}
/**
* Generate an SQL join clause for use in fetching a node listing.
*
......@@ -2762,31 +2882,6 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) {
* @{
*/
/**
* Implement hook_access().
*
* Named so as not to conflict with node_access()
*/
function node_content_access($op, $node, $account) {
$type = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);
if ($op == 'create') {
return user_access('create ' . $type . ' content', $account);
}
if ($op == 'update') {
if (user_access('edit any ' . $type . ' content', $account) || (user_access('edit own ' . $type . ' content', $account) && ($account->uid == $node->uid))) {
return TRUE;
}
}
if ($op == 'delete') {
if (user_access('delete any ' . $type . ' content', $account) || (user_access('delete own ' . $type . ' content', $account) && ($account->uid == $node->uid))) {
return TRUE;
}
}
}
/**
* Implement hook_form().
*/
......@@ -3120,45 +3215,6 @@ function node_unpublish_by_keyword_action($node, $context) {
}
}
/**
* Helper function to generate standard node permission list for a given type.
*
* @param $type
* The machine-readable name of the node type.
* @return array
* An array of permission names and descriptions.
*/
function node_list_permissions($type) {
$info = node_type_get_type($type);
$type = check_plain($info->type);
// Build standard list of node permissions for this type.
$perms = array(
"create $type content" => array(
'title' => t('Create %type_name content', array('%type_name' => $info->name)),
'description' => t('Create new %type_name content.', array('%type_name' => $info->name)),
),
"edit own $type content" => array(
'title' => t('Edit own %type_name content', array('%type_name' => $info->name)),
'description' => t('Edit %type_name content created by the user.', array('%type_name' => $info->name)),
),
"edit any $type content" => array(
'title' => t('Edit any %type_name content', array('%type_name' => $info->name)),
'description' => t('Edit any %type_name content, regardless of its author.', array('%type_name' => $info->name)),
),
"delete own $type content" => array(
'title' => t('Delete own %type_name content', array('%type_name' => $info->name)),
'description' => t('Delete %type_name content created by the user.', array('%type_name' => $info->name)),
),
"delete any $type content" => array(
'title' => t('Delete any %type_name content', array('%type_name' => $info->name)),
'description' => t('Delete any %type_name content, regardless of its author.', array('%type_name' => $info->name)),
),
);
return $perms;
}
/**
* Implement hook_requirements().
*/
......
......@@ -54,8 +54,7 @@ function poll_theme() {
* Implement hook_permission().
*/
function poll_permission() {
$perms = node_list_permissions('poll');
$perms += array(
$perms = array(
'vote on polls' => array(
'title' => t('Vote on polls'),
'description' => t('Cast votes on polls.'),
......@@ -73,20 +72,6 @@ function poll_permission() {
return $perms;
}
/**
* Implement hook_access().
*/
function poll_access($op, $node, $account) {
switch ($op) {
case 'create':
return user_access('create poll content', $account);
case 'update':
return user_access('edit any poll content', $account) || (user_access('edit own poll content', $account) && ($node->uid == $account->uid));
case 'delete':
return user_access('delete any poll content', $account) || (user_access('delete own poll content', $account) && ($node->uid == $account->uid));
}
}
/**
* Implement hook_menu().
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment