book_access.module in Book access 7.2
Same filename and directory in other branches
Allows to set the access control for book nodes on a per book basis. Based on forum_access.module and tac_lite.module.
File
book_access.moduleView source
<?php
/**
* @file
*
* Allows to set the access control for book nodes on a per book basis.
* Based on forum_access.module and tac_lite.module.
*/
final class BookAccess {
/**
* The minimum API version with which the module is compatible.
*/
const API_COMPATIBLE_VERSION = '2.5';
/**
* The API version implemented by the module.
*/
const API_VERSION = '2.5';
/**
* Adds author grants to book pages.
*
* @param $bid
* The book ID.
* @param $uid
* The user ID of the book author.
* @param $grants
* An array of grants, in the format @code $grants[$grant] @endcode,
* where @code $grant @endcode is a string between 'grant_view',
* 'grant_update', 'grant_delete', 'grant_admin_access', 'grant_add_child',
* 'grant_edit_outline'.
*/
public static function addAuthorGrants($bid, $uid, array $grants) {
$row = new stdClass();
$row->nid = $bid;
$row->uid = $uid;
$bool = db_query_range("SELECT 1 FROM {book_access_author} WHERE nid = :nid AND uid = :uid", 0, 1, array(
':nid' => $bid,
':uid' => $uid,
))
->fetchField();
foreach (self::grantIDs() as $id) {
$row->{$id} = !empty($grants[$id]);
}
drupal_write_record('book_access_author', $row, $bool ? array(
'nid',
'uid',
) : array());
}
/**
* Adds role grants to book pages.
*
* @param $bid
* The book ID.
* @param $rids
* An array of role IDs for which to add the book grants.
* @param $grants
* An array of grants, in the format @code $grants[$grant][$rid] @endcode,
* where @code $grant @endcode is a string between 'grant_view',
* 'grant_update', 'grant_delete', 'grant_admin_access', 'grant_add_child',
* 'grant_edit_outline', and @code $rid @endcode is the role ID.
*/
public static function addRoleGrants($bid, array $rids, array $grants) {
$row = new stdClass();
$row->nid = $bid;
foreach ($rids as $rid) {
$row->rid = $rid;
$bool = db_query_range("SELECT 1 FROM {book_access_role} WHERE nid = :nid AND rid = :rid", 0, 1, array(
':nid' => $bid,
':rid' => $rid,
))
->fetchField();
$granted = 0;
foreach (self::grantIDs() as $id) {
$row->{$id} = !empty($grants[$id][$rid]);
if ($row->{$id} != 0) {
$granted++;
}
}
if ($granted > 0) {
drupal_write_record('book_access_role', $row, $bool ? array(
'nid',
'rid',
) : array());
}
}
}
/**
* Adds user grants to book pages.
*
* @param $bid
* The book ID.
* @param $uids
* An array of user IDs for which to add the book grants.
* @param $grants
* An array of grants, in the format @code $grants[$grant][$uid] @endcode,
* where @code $grant @endcode is a string between 'grant_view',
* 'grant_update', 'grant_delete', 'grant_admin_access', 'grant_add_child',
* 'grant_edit_outline', and @code $uid @endcode is the user ID.
*/
public static function addUserGrants($bid, array $uids, array $grants) {
foreach ($uids as $uid) {
$bool = db_query_range("SELECT 1 FROM {book_access_user} WHERE nid = :nid AND uid = :uid", 0, 1, array(
':nid' => $bid,
':uid' => $uid,
))
->fetchField();
$row = new stdClass();
$row->nid = $bid;
$row->uid = $uid;
foreach (self::grantIDs() as $id) {
$row->{$id} = !empty($grants[$id][$uid]);
}
drupal_write_record('book_access_user', $row, $bool ? array(
'nid',
'uid',
) : array());
}
}
/**
* Verifies the current API version is included between two values passed as
* arguments.
*
* @param $minimum
* The minimum API version required. If the parameter is not passed, the
* method will use the constant API_COMPATIBLE_VERSION.
* @param $maximum
* The maximum version required. This argument is optional; the current API
* will be checked against this value only if it is passed to the function.
*
* @return
* TRUE, if the current API version is included between the passed values.
*/
public static function api($minimum = NULL, $maximum = NULL) {
if (!isset($minimum)) {
$minimum = self::API_COMPATIBLE_VERSION;
}
if (version_compare(self::API_VERSION, $minimum, '<')) {
return FALSE;
}
if (isset($maximum) && version_compare(self::API_VERSION, $maximum, '>')) {
return FALSE;
}
return TRUE;
}
/**
* Checks if a user has access to the book passed as argument.
*
* @param $bid
* The ID of the book to check.
* @param $grant
* The permission to check for. Can either be in the form "grant_update" or
* "update" though the former is now preferred for consistency.
* @param $account
* The user account for which the permission is checked; if it is not passed,
* the permission is checked against the current logged in user.
*
* @return
* TRUE if the user has the permission, FALSE otherwise.
*/
public static function checkGrant($bid, $grant, $account = NULL) {
static $queries = NULL;
if ($queries == NULL) {
$queries = array(
"book_access_author",
"book_access_role",
"book_access_user",
);
}
if (!isset($account)) {
$account = $GLOBALS['user'];
}
if (!preg_match('/^grant_/', $grant)) {
$grant = "grant_{$grant}";
}
$roles = array_keys($account->roles);
$resultSets = array();
foreach ($queries as $table) {
$queryObj = db_select($table, $table);
$queryObj
->condition("nid", $bid, "=");
if ($table == 'book_access_role') {
$queryObj
->condition("rid", $roles, "IN");
}
else {
$queryObj
->condition("uid", $account->uid, "=");
}
$queryObj
->fields($table, array(
$grant,
))
->orderBy($grant, 'DESC')
->range(0, 1);
$resultSets[$table] = $queryObj
->execute();
}
$rowCount = 0;
$grantCount = 0;
$explicitTables = array();
foreach ($resultSets as $table => $resultSet) {
if ($resultSet
->rowCount() > 0) {
$row = $resultSet
->fetchAssoc();
$explicitTables[$table] = TRUE;
++$rowCount;
$grantCount += (int) $row[$grant];
}
}
$hasPermission = $grantCount > 0;
// if our row count is less than 3, that means taht we are missing an explicit
// permissions entry in one of the tables. iterate and find the missing ones
// and check the defaults instead.
if (!$hasPermission && $rowCount < 3) {
$node = node_load($bid);
// check default author permissions first
if (!isset($explicitTables['book_access_author'])) {
$authorDefaults = variable_get("book_access_default_author_access");
$hasPermission = $account->uid == $node->uid && in_array($grant, $authorDefaults);
}
// then, failing that, check default role permissions
if (!$hasPermission && !isset($explicitTables['book_access_role'])) {
foreach ($roles as $role) {
$roleDefaults = variable_get("book_access_default_role_{$role}_access");
$hasPermission = in_array($grant, $roleDefaults);
if ($hasPermission) {
break;
}
}
}
}
return $hasPermission;
}
/**
* Resets the book access grants from the database.
*
* NOTE: once a grant has been created, it is merely set to 0 to avoid using
* defaults.
*
* @param $value
* The value to look for.
* param $field
* The database field where to look the value. The currently accepted
* values are 'bid', 'nid', 'uid', 'rid'.
* @param $types
* An array of grants types for which the function deletes records; the
* currently used values are 'author', 'role', 'user'. When this parameter
* is not passed, the method cues off the $field setting.
*/
public static function deleteGrants($value, $field = 'nid', array $types = NULL) {
if (isset($types)) {
$tables = array();
foreach ($types as $type) {
switch ($type) {
case 'author':
case 'role':
case 'user':
$tables[] = "book_access_{$type}";
break;
}
}
}
else {
switch ($field) {
case 'bid':
case 'nid':
$tables = array(
'book_access_author',
'book_access_role',
'book_access_user',
);
break;
case 'uid':
$tables = array(
'book_access_author',
'book_access_user',
);
break;
case 'rid':
$tables = array(
'book_access_role',
);
break;
default:
$tables = array();
}
}
foreach ($tables as $table) {
db_update($table)
->fields(array(
"grant_admin_access" => 0,
"grant_update" => 0,
"grant_delete" => 0,
"grant_add_child" => 0,
"grant_edit_outline" => 0,
"grant_view" => 0,
))
->condition($field == "bid" ? "nid" : $field, $value, '=')
->execute();
}
}
/**
* Returns the book author grants.
*
* @param $bid
* The book ID.
* @param $uid
* The user ID for the book author.
* @param $defaults
* An array containing the default values for the grants.
*
* @return
* An array of grants, in the format @code $grants[$grant] @endcode,
* where @code $grant @endcode is a string between 'grant_view',
* 'grant_update', 'grant_delete', 'grant_admin_access', 'grant_add_child',
* 'grant_edit_outline'.
*/
public static function getAuthorGrants($bid, $uid, array $defaults = array()) {
$grants = db_query_range('SELECT * FROM {book_access_author} WHERE nid = :nid AND uid = :uid', 0, 1, array(
':nid' => $bid,
':uid' => $uid,
))
->fetchAssoc();
if (!$grants) {
$defaults = array_filter($defaults);
foreach (self::grantIDs() as $id) {
$grants[$id] = !empty($defaults[$id]);
}
}
return $grants;
}
/**
* Lists all the books to which the current user has access.
*
* @param $account
* The user account to use; if NULL, the currently logged in user account
* will be used.
* @param $grants
* An array containing one or more values between 'view', 'update',
* 'delete', 'admin_access', 'add_child', and 'edit_outline'.
*
* @return
* An array containing the node ID of the books to which the user has access.
*/
public static function getBookList(array $grants = array(
'update',
), $account = NULL) {
$permitted_bids = array();
if (!isset($account)) {
$account = $GLOBALS['user'];
}
foreach ($grants as $grant) {
$result = db_query("SELECT nid FROM {book_access_author} WHERE uid = :uid AND grant_{$grant} > 0", array(
':uid' => $account->uid,
));
foreach ($result as $book) {
$permitted_bids[$book->nid] = $book->nid;
}
$roles = array_keys($account->roles);
$result = db_query("SELECT nid FROM {book_access_role} WHERE rid IN (:rid) AND grant_{$grant} > 0", array(
':rid' => $roles,
));
foreach ($result as $book) {
$permitted_bids[$book->nid] = $book->nid;
}
$result = db_query("SELECT nid FROM {book_access_user} WHERE uid = :uid AND grant_{$grant} > 0", array(
':uid' => $account->uid,
));
foreach ($result as $book) {
$permitted_bids[$book->nid] = $book->nid;
}
}
return $permitted_bids;
}
/**
* Gets the list of grant records assigned to a book.
*
* @param $bid
* The ID of the book for which the function returns the grant records.
* @param $types
* An array of grants types for which the function returns the records; the
* currently used values are 'author', 'role', 'user'.
*
* @return
* The array of grant records for the specified book.
*/
public static function getGrantRecords($bid, array $types = array(
'author',
'role',
'user',
)) {
$grants = array();
$info = array();
foreach ($types as $type) {
switch ($type) {
case 'author':
$info[] = array(
'table' => 'book_access_author',
'gid' => 'uid',
);
break;
case 'role':
$info[] = array(
'table' => 'book_access_role',
'gid' => 'rid',
);
break;
case 'user':
$info[] = array(
'table' => 'book_access_user',
'gid' => 'uid',
);
break;
}
}
foreach ($info as $data) {
$result = db_query("SELECT * FROM {" . db_escape_table($data['table']) . "} WHERE nid = :nid", array(
':nid' => $bid,
));
foreach ($result as $grant) {
$grants[] = array(
'realm' => $data['table'],
'gid' => $grant->{$data['gid']},
'grant_view' => $grant->grant_view,
'grant_update' => $grant->grant_update,
'grant_delete' => $grant->grant_delete,
'priority' => variable_get('book_access_priority', 0),
);
}
}
return $grants;
}
/**
* Returns the role book grants.
*
* @param $bid
* The book ID.
* @param $roles
* The variables where to store the value returned by user_roles().
* @param $defaults
* An array containing the default values for the grants.
*
* @return
* An array of grants, in the format @code $grants[$grant][$rid] @endcode,
* where @code $grant @endcode is a string between 'grant_view',
* 'grant_update', 'grant_delete', 'grant_admin_access', 'grant_add_child',
* 'grant_edit_outline', and @code $rid @endcode is the role ID.
*/
public static function getRoleGrants($bid, &$roles, array $defaults = array()) {
$grants = array(
'grant_view' => array(),
'grant_update' => array(),
'grant_delete' => array(),
'grant_admin_access' => array(),
'grant_add_child' => array(),
'grant_edit_outline' => array(),
);
$roles = user_roles();
$rcopy = $roles;
$rids = array_keys($roles);
$result = db_query("SELECT * FROM {book_access_role} WHERE nid = :nid AND rid IN (:rid)", array(
':nid' => $bid,
':rid' => $rids,
));
// Build the role access permissions for the book.
if ($result
->rowCount() > 0) {
foreach ($result as $access) {
unset($rcopy[$access->rid]);
foreach (self::grantIDs() as $id) {
$grants[$id][$access->rid] = !empty($access->{$id});
}
}
}
else {
foreach ($rids as $rid) {
$roleDefaults = variable_get("book_access_default_role_{$rid}_access");
if ($roleDefaults) {
unset($rcopy[$rid]);
foreach (self::grantIDs() as $id) {
$grants[$id][$rid] = in_array($id, $roleDefaults);
}
}
}
}
$defaults = array_filter($defaults);
// Set the default role access permissions for the roles that don't have
// access permissions already set.
foreach (self::grantIDs() as $id) {
foreach ($rcopy as $rid => $name) {
$grants[$id][$rid] = !empty($defaults[$id]);
}
}
return $grants;
}
/**
* Returns the user book grants.
*
* @param $bid
* The book ID.
* @param $uids
* The variables where to store the user IDs.
* @param $defaults
* An array containing the default values for the grants.
*
* @return
* An array of grants, in the format @code $grants[$grant][$uid] @endcode,
* where @code $grant @endcode is a string between 'grant_view',
* 'grant_update', 'grant_delete', 'grant_admin_access', 'grant_add_child',
* 'grant_edit_outline', and @code $uid @endcode is the user ID.
*/
public static function getUserGrants($bid, &$uids) {
$grants = array(
'grant_view' => array(),
'grant_update' => array(),
'grant_delete' => array(),
'grant_admin_access' => array(),
'grant_add_child' => array(),
'grant_edit_outline' => array(),
);
$uids = array();
$result = db_query("SELECT * FROM {book_access_user} bau INNER JOIN {users} u ON u.uid = bau.uid WHERE bau.nid = :nid", array(
':nid' => $bid,
));
foreach ($result as $access) {
$uid = $access->uid;
$uids[$uid] = $uid;
foreach (self::grantIDs() as $id) {
$grants[$id][$uid] = !empty($access->{$id});
}
}
return $grants;
}
/**
* Returns the grant IDs implemented by the module.
*/
public static function grantIDs() {
return array(
'grant_view',
'grant_update',
'grant_delete',
'grant_admin_access',
'grant_add_child',
'grant_edit_outline',
);
}
/**
* Returns the default access permissions.
*/
public static function defaultGrants() {
return array(
'grant_view',
);
}
/**
* Returns the default author access permissions.
*/
public static function defaultAuthorGrants() {
static $defaults = NULL;
if (!$defaults) {
$defaults = self::grantIDs();
unset($defaults[array_search('grant_admin_access', $defaults)]);
$defaults = array_values($defaults);
}
return $defaults;
}
/**
* Restricts the options available to who moves book pages between books.
*
* @param $options
* The options array used from book_outline_form() and the book edit form
* for the list of books to which the page can be moved to.
* @param $account
* The user account to use; if NULL, the currently logged in user account
* will be used.
*/
public static function restrictOptions(&$options, $account = NULL) {
if (!isset($account)) {
$account = $GLOBALS['user'];
}
if (user_access('administer nodes', $account)) {
return;
}
$permitted_bids = self::getBookList(array(
'update',
), $account);
foreach ($options as $bid => $value) {
if ($bid > 0 && !isset($permitted_bids[$bid])) {
unset($options[$bid]);
}
}
}
/**
* Sets the author grants for book pages.
*
* The method delete the author grants before to set the new ones.
*
* @param $bid
* The book ID.
* @param $uid
* The user ID of the book author.
* @param $grants
* An array of grants, in the format @code $grants[$grant] @endcode,
* where @code $grant @endcode is a string between 'grant_view',
* 'grant_update', 'grant_delete', 'grant_admin_access', 'grant_add_child',
* 'grant_edit_outline'.
*/
public static function setAuthorGrants($bid, $uid, array $grants) {
db_delete('book_access_author')
->condition('nid', $bid)
->execute();
self::addAuthorGrants($bid, $uid, $grants);
}
/**
* Sets the role grants for book pages.
*
* The method delete the role grants before to set the new ones.
*
* @param $bid
* The book ID.
* @param $rids
* An array of role IDs for which to add the book grants.
* @param $grants
* An array of grants, in the format @code $grants[$grant][$rid] @endcode,
* where @code $grant @endcode is a string between 'grant_view',
* 'grant_update', 'grant_delete', 'grant_admin_access', 'grant_add_child',
* 'grant_edit_outline', and @code $rid @endcode is the role ID.
*/
public static function setRoleGrants($bid, array $rids, array $grants) {
db_delete('book_access_role')
->condition('nid', $bid)
->execute();
self::addRoleGrants($bid, $rids, $grants);
}
/**
* Sets the user grants for book pages.
*
* The method delete the user grants before to set the new ones.
*
* @param $bid
* The book ID.
* @param $uids
* An array of user IDs for which to add the book grants.
* @param $grants
* An array of grants, in the format @code $grants[$grant][$uid] @endcode,
* where @code $grant @endcode is a string between 'grant_view',
* 'grant_update', 'grant_delete', 'grant_admin_access', 'grant_add_child',
* 'grant_edit_outline', and @code $uid @endcode is the user ID.
*/
public static function setUserGrants($bid, array $uids, array $grants) {
db_delete('book_access_user')
->condition('nid', $bid)
->execute();
self::addUserGrants($bid, $uids, $grants);
}
/**
* @param $rid
* The role id to set the default for.
* @param $rname
* The optional name of the role. If specified, this saves a database
* trip, as otherwise this method uses $rid to look up the name.
*
* Based on the role name, this initializes the default grants for the role
* id. This is only intended to be used during hook_init() or when creating a
* brand new role.
*/
public static function setDefaultForRole($rid, $rname = NULL) {
if (!$rname) {
$role = user_role_load($rid);
if ($role === FALSE) {
drupal_set_message(t("Could not set default book_access grants for role: @rid, role not found", array(
'@rid' => $rid,
)), "error");
return;
}
$rname = $role->rid;
}
if ($rname == 'administrator') {
$defaultToUse = self::grantIDs();
}
else {
$defaultToUse = self::defaultGrants();
}
if (variable_get("book_access_default_role_{$rid}_access") === NULL) {
variable_set("book_access_default_role_{$rid}_access", $defaultToUse);
}
}
/**
* Resets book permissions to its defaults, ignoring user-specific ones.
*/
public static function resetToDefault($nid) {
$node = node_load($nid);
$roles = user_roles();
$authorDefaults = variable_get('book_access_default_author_access');
BookAccess::setAuthorGrants($nid, $node->uid, drupal_map_assoc($authorDefaults));
// clear out the existing role grants and add on to it
BookAccess::setRoleGrants($nid, array_keys($roles), array());
$roleGrantsToAdd = array();
foreach ($roles as $rid => $rname) {
$roleDefaults = variable_get("book_access_default_role_{$rid}_access");
foreach ($roleDefaults as $grant) {
$roleGrantsToAdd[$grant][$rid] = TRUE;
}
}
BookAccess::addRoleGrants($nid, array_keys($roles), $roleGrantsToAdd);
}
/**
* Updates the grants for a book.
*
* @param $bid
* The book ID.
* @param $fields
* The fields to update.
* @param $types
* An array containing the grant types; the currently used values are
* 'author', 'role', 'user'. It is responsibility of the caller to use
* values for $types for which $field is valid.
*/
public static function updateGrants($bid, array $fields, array $types = array(
'author',
'role',
'user',
)) {
foreach ($types as $type) {
switch ($type) {
case 'author':
case 'role':
case 'user':
$table = "book_access_{$type}";
break;
default:
$table = '';
}
if ($table) {
db_update($table)
->fields($fields)
->condition('nid', $bid)
->execute();
}
}
}
/*
* Writes the grant records to the Drupal node access table.
*
* @param $node
* The node object for the book page.
* @param $types
* An array of grants types that are written; the currently used values are
* 'author', 'role', 'user'.
*/
public static function writeGrantRecords($node, array $types = array(
'author',
'role',
'user',
)) {
if (!empty($node->nid) && !empty($node->book['bid'])) {
foreach ($types as $type) {
switch ($type) {
case 'author':
case 'role':
case 'user':
$table = "book_access_{$type}";
break;
default:
$table = '';
}
if ($table && ($grants = self::getGrantRecords($node->book['bid'], array(
$type,
)))) {
node_access_write_grants($node, $grants, $table, TRUE);
}
}
}
}
}
/**
* Implements hook_init().
*
* Sets up some default variables.
*/
function book_access_init() {
$roles = user_roles();
$authorDefaults = BookAccess::defaultAuthorGrants();
if (variable_get('book_access_default_author_access') === NULL) {
variable_set('book_access_default_author_access', $authorDefaults);
}
foreach ($roles as $rid => $rname) {
BookAccess::setDefaultForRole($rid, $rname);
}
}
/**
* Implements hook_user_role_insert().
*
* Makes sure to set default viewability when a new role is created.
*/
function book_access_user_role_insert($role) {
BookAccess::setDefaultForRole($role->rid, $role->name);
}
/**
* Implements hook_node_insert().
*
* Specifically targets creation of book nodes to set some default permissions
*/
function book_access_node_insert($node) {
if (isset($node->book['bid']) && $node->book['bid'] && $node->nid == $node->book['bid']) {
BookAccess::setAuthorGrants($node->book['bid'], $node->uid, drupal_map_assoc($node->uid == 0 ? BookAccess::defaultGrants() : variable_get("book_access_default_author_access")));
$roles = user_roles();
$rids = array_keys($roles);
foreach ($rids as $rid) {
$roleDefaults = variable_get("book_access_default_role_{$rid}_access", array());
foreach ($roleDefaults as $default) {
$roleGrants[$default][$rid] = TRUE;
}
}
BookAccess::setRoleGrants($node->book['bid'], $rids, $roleGrants);
}
}
/**
* Implements hook_node_update().
*
* Makes sure defaults propagate to pages that have been 'upgraded' to a book.
*/
function book_access_node_update($node) {
if (isset($node->book['bid']) && $node->book['bid']) {
// check for existing permissions
$rowCount = db_select('book_access_author', 'book_access_author')
->condition('nid', $node->book['bid'], '=')
->condition('uid', $node->uid)
->countQuery()
->execute()
->fetchField();
if ($rowCount == 0) {
BookAccess::setAuthorGrants($node->book['bid'], $node->uid, drupal_map_assoc($node->uid == 0 ? BookAccess::defaultGrants() : variable_get("book_access_default_author_access")));
}
$roles = user_roles();
$rids = array_keys($roles);
$roleResultSet = db_select('book_access_role', 'book_access_role')
->condition('nid', $node->book['bid'], '=')
->condition('rid', $rids, 'IN')
->fields('book_access_role', array(
'rid',
))
->distinct()
->execute();
if ($roleResultSet
->rowCount() < count($rids)) {
// fill in the missing ones
$existingRids = array();
foreach ($roleResultSet as $row) {
$existingRids[] = $row->rid;
}
$missingRids = array_diff($rids, $existingRids);
foreach ($missingRids as $rid) {
$defaultToUse = variable_get("book_access_role_{$rid}_default");
if ($defaultToUse !== NULL) {
$roleDefaults = array();
foreach ($defaultToUse as $grant) {
$roleDefaults[$grant] = $rid;
}
BookAccess::addRoleGrants($node->book['bid'], array(
$rid,
), $roleDefaults);
}
}
}
}
}
/**
* Implements hook_form_alter().
*
* @see book_outline_form()
* @see book_access_outline_form_submit()
* @see book_access_edit_form_submit()
*
*/
function book_access_form_alter(&$form, &$form_state, $form_id) {
if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id) {
if (isset($form['book']['bid']['#options'])) {
BookAccess::restrictOptions($form['book']['bid']['#options']);
}
$form['#submit'][] = 'book_access_edit_form_submit';
}
elseif ($form_id == 'book_outline_form') {
if (isset($form['book']['bid']['#options'])) {
BookAccess::restrictOptions($form['book']['bid']['#options']);
}
$form['#submit'][] = 'book_access_outline_form_submit';
if (isset($form['remove'])) {
$form['remove']['#submit'][] = 'book_access_edit_form_submit';
}
}
}
/**
* Implements hook_menu_alter().
*
* @see _book_access_outline_access()
* @see book_access_outline_remove_access()
*/
function book_access_menu_alter(&$items) {
if (isset($items['node/%node/outline'])) {
$items['node/%node/outline']['access callback'] = '_book_access_outline_access';
}
if (isset($items['node/%node/outline/remove'])) {
$items['node/%node/outline/remove']['access callback'] = '_book_access_outline_remove_access';
}
}
/**
* Implements hook_node_delete().
*/
function book_access_node_delete($node) {
BookAccess::deleteGrants($node->nid);
}
/**
* Implements hook_node_grants().
*/
function book_access_node_grants($account, $op) {
$grants = array();
$grants['book_access_author'] = array(
$account->uid,
);
$grants['book_access_role'] = array_keys($account->roles);
$grants['book_access_user'] = array(
$account->uid,
);
return $grants;
}
/**
* Implements hook_node_view_alter().
*
* Enables the link "Add child page" only for users who have the right
* permission.
*/
function book_access_node_view_alter(&$build) {
if (!empty($node->book['bid']) && !empty($build['links']['book']['#links'])) {
$links = $build['links']['book']['#links'];
$node = $build['#node'];
if (user_access('administer nodes')) {
return;
}
if (!empty($links['book_add_child'])) {
$bool = (user_access('add content to books') && BookAccess::checkGrant($node->book['bid'], 'add_child') || user_access('administer book outlines')) && node_access('create', variable_get('book_child_type', 'book')) && $node->status == 1 && $node->book['depth'] < MENU_MAX_DEPTH;
if (!$bool) {
unset($links['book_add_child']);
}
}
}
}
/**
* Implements hook_node_access_explain().
*
* hook_node_access_explain() is defined in devel_node_access.module, which
* helps you to figure out how node access works and what permissions are
* currently granted.
*/
function book_access_node_access_explain($row) {
static $roles = NULL;
$result = array();
if ($row->realm == 'book_access_author') {
$result = array(
t('Grants for book authors'),
);
}
elseif ($row->realm == 'book_access_role') {
if (!isset($roles)) {
$roles = user_roles();
}
if (isset($roles[$row->gid])) {
$result = array(
t('Grants for users of role %role', array(
'%role' => $roles[$row->gid],
)),
);
}
else {
$result = array(
t('Unknown group ID %gid', array(
'%gid' => $row->gid,
)),
);
}
}
elseif ($row->realm == 'book_access_user') {
if ($user = user_load($row->gid)) {
$result = array(
t('Grants for user %username', array(
'%username' => $user->name,
)),
);
}
else {
$result = array(
t('Unknown user ID %gid', array(
'%gid' => $row->gid,
)),
);
}
}
return $result;
}
/**
* Implements hook_node_access_records().
*
* Returns a list of grant records for the book node object passed as argument.
* If we have a book child page, we return the access settings of the top level
* parent book page node.
*/
function book_access_node_access_records($node) {
$grants = array();
if (!empty($node->book['bid'])) {
$grants = BookAccess::getGrantRecords($node->book['bid']);
if (is_array($grants) && !$node->status) {
// unpublished node, grant_view should be off for all types (author,role,user)
foreach ($grants as &$grant) {
$grant['grant_view'] = 0;
}
}
}
return $grants;
}
/**
* Implements hook_permission().
*/
function book_access_permission() {
return array(
'administer book access' => array(
'title' => t('Administer book access'),
),
'administer access of any book' => array(
'title' => t('Administer access of any book'),
),
'administer access of own books' => array(
'title' => t('Administer access of own books'),
),
);
}
/**
* Implements hook_user_delete().
*/
function book_access_user_delete($account) {
BookAccess::deleteGrants($account->uid, 'uid');
}
/**
* Implements hook_node_view().
*
* We want to hide the "Add Child Page" link if the current user
* doesn't have permission for it.
*/
function book_access_node_view($node, $view_mode, $langcode) {
if (isset($node->content['links']['book']) && isset($node->content['links']['book']['#links']['book_add_child'])) {
if (!BookAccess::checkGrant($node->book['bid'], 'grant_add_child')) {
unset($node->content['links']['book']['#links']['book_add_child']);
}
}
}
/**
* Form submission callback for node_form(), and book_outline_form().
*
* @see node_form()
* @see book_outline_form()
* @see book_access_form_alter()
*/
function book_access_edit_form_submit($form, &$form_state) {
BookAccess::writeGrantRecords($form['#node']);
}
/**
* Form submission callback for book_outline_form().
*
* @see book_outline_form()
* @see book_access_form_alter()
*/
function book_access_outline_form_submit($form, &$form_state) {
if (isset($form['plid']) && $form['plid'] != $form_state['values']['plid']) {
BookAccess::writeGrantRecords($form['#node']);
}
}
/**
* Determines if the outline tab is accessible.
*
* @see book_access_menu_alter()
*/
function _book_access_outline_access($node) {
if (empty($node->book['bid'])) {
return FALSE;
}
$view_access = node_access('view', $node);
if (user_access('administer book outlines') && $view_access) {
return TRUE;
}
return BookAccess::checkGrant($node->book['bid'], 'edit_outline') && $view_access;
}
/**
* Determines if the user can remove nodes from the outline.
*
* @see book_access_menu_alter()
*/
function _book_access_outline_remove_access($node) {
$bool = !empty($node->book['bid']) && $node->book['bid'] != $node->nid && _book_access_outline_access($node);
return $bool;
}
Functions
Classes
Name | Description |
---|---|
BookAccess | @file |