/** * @defgroup node_access Node access rights * @{ * The node access system determines who can do what to which nodes. * * In determining access rights for a node, node_access() first checks * whether the user has the "administer nodes" 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. * * In node listings, the process above is followed except that * hook_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. * * To see how to write a node access module of your own, see * node_access_example.module. */ /** * Determine whether the current user may perform the given operation on the * specified node. * * @param $op * The operation to be performed on the node. Possible values are: * - "view" * - "update" * - "delete" * - "create" * @param $node * The node object (or node array) on which the operation is to be performed, * or node type (e.g. 'forum') for "create" operation. * @return * TRUE if the operation may be performed. */ function node_access($op, $node = NULL) { global $user; // Convert the node to an object if necessary: if ($op != 'create') { $node = (object)$node; } // If the node is in a restricted format, disallow editing. if ($op == 'update' && !filter_access($node->format)) { return FALSE; } if (user_access('administer nodes')) { return TRUE; } if (!user_access('access content')) { return FALSE; } // // Modification // // For the content types we know about // // Can't use node_invoke(), because the access hook takes the $op parameter // before the $node parameter. $module = node_get_types('module', $node); if ($module == 'node') { $module = 'node_content'; // Avoid function name collisions. } $access = module_invoke($module, 'access', $op, $node); if (!is_null($access)) { return $access; } // // Modification // // Extensible Node Access/Authorisation Capability patch: http://drupal.org/node/122173 // // Now allow other modules to have their say on access to this node $results = node_invoke_nodeapi($node, 'access', $op); // The first module that actually returns a value takes precidence over // all the others. foreach ($results as $access) { // node_invoke_nodeapi shouldn't even put NULL in it's results, but // we should check because it's pretty important to get this right if (!is_null($access)) { return $access; } } // // If the module did not override the access rights, use those set in the // node_access table. if ($op != 'create' && $node->nid && $node->status) { $grants = array(); foreach (node_access_grants($op) as $realm => $gids) { foreach ($gids as $gid) { $grants[] = "(gid = $gid AND realm = '$realm')"; } } $grants_sql = ''; if (count($grants)) { $grants_sql = 'AND ('. implode(' OR ', $grants) .')'; } $sql = "SELECT COUNT(*) FROM {node_access} WHERE (nid = 0 OR nid = %d) $grants_sql AND grant_$op >= 1"; $result = db_query($sql, $node->nid); return (db_result($result)); } // Let authors view their own nodes. if ($op == 'view' && $user->uid == $node->uid && $user->uid != 0) { return TRUE; } return FALSE; } /** * @defgroup node_content Hook implementations for user-created content types. * @{ */ /** * Implementation of hook_access(). */ function node_content_access($op, $node) { global $user; $type = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type); if ($op == 'create') { return user_access('create '. $type .' content'); } if ($op == 'update' || $op == 'delete') { if (user_access('edit '. $type .' content') || (user_access('edit own '. $type .' content') && ($user->uid == $node->uid))) { return TRUE; } } } /** * Fetch an array of permission IDs granted to the given user ID. * * The implementation here provides only the universal "all" grant. A node * access module should implement hook_node_grants() to provide a grant * list for the user. * * @param $op * The operation that the user is trying to perform. * @param $uid * The user ID performing the operation. If omitted, the current user is used. * @return * An associative array in which the keys are realms, and the values are * arrays of grants for those realms. */ function node_access_grants($op, $uid = NULL) { global $user; if (isset($uid)) { $user_object = user_load(array('uid' => $uid)); } else { $user_object = $user; } return array_merge(array('all' => array(0)), module_invoke_all('node_grants', $user_object, $op)); } == og == function og_node_grants($account, $op) { if (variable_get('og_enabled', FALSE)) { if ($op == 'view') { $grants['og_public'][] = 0; // everyone can see a public node } // get subscriptions if ($subscriptions = og_get_subscriptions($account->uid)) { foreach ($subscriptions as $key => $val) { if ($op == 'view') { $grants['og_subscriber'][] = $key; } if (($op == 'update' || $op == 'delete') && $val['is_admin']) { $grants['og_subscriber'][] = $key; } } } return $grants ? $grants : array(); } } =============== taxonomy_access =============== /** * Implementation of hook_node_grants() * Gives access to taxonomies based on the taxonomy_access table */ function taxonomy_access_node_grants($user, $op) { // return array('term_access' => array_keys(is_array($user->roles) ? $user->roles : array(1 => 'anonymous user'))); // // Modification - using user_all_roles_array instead of $user->roles; // return array('term_access' => array_keys(is_array(user_all_roles_array($user)) ? user_all_roles_array($user) : array(1 => 'anonymous user'))); } ==== node ==== In the node module, this collects the grants from the other modules: /** * This function will call module invoke to get a list of grants and then * write them to the database. It is called at node save, and should be * called by modules whenever something other than a node_save causes * the permissions on a node to change. * * This function is the only function that should write to the node_access * table. * * @param $node * The $node to acquire grants for. */ function node_access_acquire_grants($node) { $grants = module_invoke_all('node_access_records', $node); if (!$grants) { $grants[] = array('realm' => 'all', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0); } else { // retain grants by highest priority $grant_by_priority = array(); foreach ($grants as $g) { $grant_by_priority[intval($g['priority'])][] = $g; } krsort($grant_by_priority); $grants = array_shift($grant_by_priority); } node_access_write_grants($node, $grants); } == og == function og_node_access_records($node) { // don't write records if og access control is disabled or the node type is omitted or node is a group // if you want group nodes to be protected too, perhaps write a complementary node_access module. lets discuss. if (og_is_omitted_type($node->type) || !variable_get('og_enabled', FALSE) || og_is_group_type($node->type)) { return; } if (is_array($node->og_groups)) { foreach ($node->og_groups as $gid) { // we write a broad grant here but og_node_grants() only issues it selectively. // $grants[] = array('realm' => 'og_subscriber', 'gid' => $gid, 'grant_view' => 1, 'grant_update' => 1, 'grant_delete' => 1); // Modification - changed priority to 2. Lower than TAC (which is 0). $grants[] = array('priority' => 0, 'realm' => 'og_subscriber', 'gid' => $gid, 'grant_view' => 1, 'grant_update' => 1, 'grant_delete' => 1); } } if ($node->og_public) { $grants[] = array('realm' => 'og_public', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0); } // propose a deny for non public nodes whose type matters to og and aren't in a group if (!count($grants)) { $grants[] = array('priority' => 10, 'realm' => 'og_public', 'gid' => 0, 'grant_view' => 0, 'grant_update' => 0, 'grant_delete' => 0); } return $grants; } =============== taxonomy_access =============== /** * Implementation of hook_node_access_records(). */ function taxonomy_access_node_access_records($node) { if (taxonomy_access_disabling() || !isset($node->nid)) { return; } $grants = array(); $where = "WHERE n.nid = ".$node->nid; $result = db_query("SELECT n.nid, ta.rid, BIT_OR(ta.grant_view) AS grant_view, BIT_OR(ta.grant_update) AS grant_update, BIT_OR(ta.grant_delete) AS grant_delete FROM {term_node} n INNER JOIN {term_access} ta ON n.tid = ta.tid $where GROUP BY n.nid, ta.rid"); while($row = db_fetch_object($result)) { if ($row) { $grant_view = ($row->grant_view == 1) ? 1 : 0; $grant_update = ($row->grant_update == 1) ? 1 : 0; $grant_delete = ($row->grant_delete == 1) ? 1 : 0; $grants[] = array( 'realm' => 'term_access', 'gid' => $row->rid, 'grant_view' => $grant_view, 'grant_update' => $grant_update, 'grant_delete' => $grant_delete, 'priority' => 0, // Modified - changed priority to 1 to see what happens. OG is set at 0. // 'priority' => 1, ); } } // Determine if node doesn't belong to a category $where = "AND n.nid = ".$node->nid; $result = db_query("SELECT n.nid, ta.* FROM {node} n LEFT JOIN {term_node} t ON t.nid=n.nid LEFT JOIN {term_access} ta ON ta.tid = 0 WHERE t.nid IS NULL $where"); while($row = db_fetch_object($result)) { if ($row) { $grant_view = ($row->grant_view == 1) ? 1 : 0; $grant_update = ($row->grant_update == 1) ? 1 : 0; $grant_delete = ($row->grant_delete == 1) ? 1 : 0; $grants[] = array( 'realm' => 'term_access', 'gid' => $row->rid, 'grant_view' => $grant_view, 'grant_update' => $grant_update, 'grant_delete' => $grant_delete, 'priority' => 0, ); } } return $grants; } NODEAPI /** * Implementation of hook_nodeapi(). */ function taxonomy_access_nodeapi(&$node, $op, $arg = 0) { switch ($op) { // // Modified // // Added 2007-02-26 - Access module to return OG access in concert with TAC access. // case 'access': $access = FALSE; $og_access = og_node_access($arg, $node); $tac_access = taxonomy_access_node_access($arg, $node); if ($tac_access === TRUE && $og_access == FALSE) $access = FALSE; if ($tac_access === FALSE) $access = FALSE; if ($tac_access === TRUE && $og_access == TRUE) $access = TRUE; return $access; break; -------------- =============== taxonomy_access =============== // // Modification // // Added 2007-02-26 - This module checks user's permissions for $op on $node restricted to Taxnonmy Access Control access only. // Returns TRUE or FALSE // function taxonomy_access_node_access($op, $node = NULL) { global $user; $uid = $user->uid; if ($op != 'create' && $node->nid && $node->status) { // Discovered that I needed to continue using user->roles to get non-group roles. // will get group roles using og_users_roles and og_ancestry // if (isset($user) && is_array($user->roles)) { $rids = array_keys($user->roles); } else { $rids[] = 1; } $sql = "SELECT COUNT(*) FROM {node_access} na"; $sql .= " LEFT OUTER JOIN {og_users_roles} ogr ON ogr.rid = na.gid"; $sql .= " LEFT OUTER JOIN {og_ancestry} oga ON oga.nid = na.nid"; $sql .= " LEFT OUTER JOIN {og_uid} ogu on ogu.nid = na.nid"; $sql .= " WHERE (na.nid = 0 OR na.nid = %d) AND ((na.realm = 'term_access' AND na.gid in ('".implode("','",$rids)."')) OR (ogr.uid = " . $uid . " AND na.realm = 'term_access' AND oga.group_nid = ogr.gid) )"; $sql .= " AND (na.grant_$op >= 1 OR (ogu.is_admin = 1 AND ogu.uid = ".$uid.") )"; $result = db_query($sql, $node->nid); $output = (db_result($result)); if ($output == 0) return FALSE; if ($output > 0) return TRUE; } } == og == // // Modification // // Added 2007-02-26 - This module checks user's permissions for $op on $node restricted to OG access only. // Returns TRUE or FALSE // function og_node_access($op, $node = NULL) { global $user; $uid = $user->uid; if ($op != 'create' && $node->nid && $node->status) { if (isset($user) && is_array($user->og_groups)) { $gids = array_keys($user->og_groups); } else { $gids[] = 0; } // $sql = "SELECT COUNT(*) FROM {node_access} na LEFT OUTER JOIN {og_users_roles} ogr ON ogr.rid = na.gid WHERE (na.nid = 0 OR na.nid = %d) AND ((na.realm = 'og_public' and na.gid = 0) OR (na.realm = 'og_subscriber' AND na.gid in ('".implode("','",$gids)."')) ) AND na.grant_$op >= 1"; // $sql = "SELECT COUNT(*) FROM {node_access} na LEFT OUTER JOIN {og_users_roles} ogr ON ogr.rid = na.gid WHERE (na.nid = 0 OR na.nid = %d) AND ((na.realm = 'og_public' and na.gid = 0) OR (na.realm = 'og_subscriber' AND na.gid in ('".implode("','",$gids)."')) OR (na.realm = 'term_access' AND na.nid in ('".implode("','",$gids)."')) ) AND na.grant_$op >= 1"; $sql = "SELECT COUNT(*) FROM {node_access} na LEFT OUTER JOIN {og_uid} ogu on ogu.nid = na.nid WHERE (na.nid = 0 OR na.nid = %d) AND ((na.realm = 'og_public' and na.gid = 0) OR (na.realm = 'og_subscriber' AND na.gid in ('".implode("','",$gids)."')) OR (na.realm = 'term_access' AND na.nid in ('".implode("','",$gids)."')) ) AND ((na.grant_$op >= 1) OR (ogu.is_admin = 1 AND ogu.uid = ".$uid.") )"; $result = db_query($sql, $node->nid); $output = (db_result($result)); if ($output == 0) return FALSE; if ($output > 0) return TRUE; } }