- <?php
- * @file
- * Hook implementations for the Node Access Example module.
- */
-
- * @defgroup node_access_example Example: Node Access
- * @ingroup examples
- * @{
- * This example demonstrates how to use the node access.
- *
- * This is an example demonstrating how to grant or deny access to nodes using
- * the node access system.
- *
- * This module will add a 'private' flag for each node, which the node's author
- * can manage. Nodes marked private can only be viewed, edited, or deleted by
- * the author. However, not everything is as private as it seems on the
- * Internet, and so we need to implement some ways to allow other users to
- * manage this 'private' content.
- *
- * We will use the node grant system to specify which users are allowed to view,
- * edit, or delete 'private' content. We will also allow a user named 'foobar'
- * to have edit privileges on private content as well.
- *
- * In addition, we will provide a page which will show some minimal instructions
- * and statistics on private nodes on the site.
- *
- * We use node hooks to put a single marker on a node, called 'private'. The
- * marker is implemented by a database table which has one row per node simply
- * indicating the node is private. If the "private" marker is set, users other
- * than the owner and privileged users are denied access.
- *
- * Standard permissions are defined which allow users with
- * 'access any private content' or 'edit any private content' to override the
- * 'private' node access restrictions.
- *
- * A separate access realm grants privileges to each node's author. They can
- * always view, edit, and delete their own private nodes.
- *
- * The only page provided by this module gives a rundown of how many nodes are
- * marked private, and how many of those are accessible to the current user.
- * This demonstrates the use of the 'node_access' tag in node queries,
- * preventing disclosure of information which should not be shown to users who
- * don't have the proper permissions.
- *
- * The most relevant functions are:
- * - node_access_example_permission()
- * - node_access_example_node_access()
- * - node_access_example_node_access_records()
- * - node_access_example_node_grants()
- *
- * Backdrop's node access system has three layers.
- * - User 1 and any user with 'bypass node access' permission are automatically
- * granted access.
- * - hook_node_access() gives each module the opportunity to approve or deny
- * access. Any module that returns NODE_ACCESS_DENY from hook_node_access()
- * will result in denial of access. If no module denies access and one or
- * more modules allow access, then access is granted.
- * - If no resolution has yet been reached, the node_access table is used along
- * with hook_node_grants(). (Backdrop updates the node_access table when
- * nodes are saved, by calling hook_node_access_records().)
- *
- * Note that the hook_node_grants()/hook_node_access_records() layer is a
- * first-grant-wins system, which means a module using it can't deny access to
- * a node. Contributed modules have been developed to overcome this shortcoming,
- * with their own APIs, such as
- * @link http://backdropcms.org/project/acl ACL @endlink. ACL, in fact, has
- * emerged as the more-or-less standard solution for fine-grained access
- * control, and it is used by many modules.
- *
- * @see node_access()
- * @see hook_node_access()
- * @see hook_node_grants()
- * @see hook_node_access_records()
- */
-
- * Implements hook_menu().
- *
- * This path provides a page, with some instructions for the user, and some
- * statistics about node access changes implemented by this module.
- *
- * @see hook_menu()
- */
- function node_access_example_menu() {
- $items['examples/node_access'] = array(
- 'title' => 'Node Access Example',
- 'page callback' => 'node_access_example_private_node_listing',
- 'access callback' => TRUE,
- );
- return $items;
- }
-
- * Our hook_menu() page callback function.
- *
- * Information for the user about what nodes are marked private on the system
- * and which of those the user has access to.
- *
- * The queries showing what is accessible to the current user demonstrate the
- * use of the 'node_access' tag to make sure that we don't show inappropriate
- * information to unprivileged users.
- *
- * @return array
- * A render array.
- *
- * @see page_example
- */
- function node_access_example_private_node_listing() {
- $content = '<div>' . t('This example shows how a module can use the Backdrop node access system to allow access to specific nodes. You will need to look at the code and then experiment with it by creating nodes, marking them private, and accessing them as various users.') . '</div>';
-
-
- $query = db_select('node', 'n');
- $query->addExpression('COUNT(n.nid)', 'private_count');
- $query->join('node_access_example', 'nae', 'nae.nid = n.nid');
- $num_private = $query
- ->condition('nae.private', 1)->execute()->fetchField();
-
-
- $query = db_select('node', 'n');
- $query->addExpression('COUNT(n.nid)', 'private_count');
- $query->join('node_access_example', 'nae', 'nae.nid = n.nid');
- $num_personal = $query
- ->condition('n.uid', $GLOBALS['user']->uid)
- ->condition('nae.private', 1)
- ->execute()->fetchfield();
-
- $content .= '<div>' . t('There are currently @num private nodes in the system @num_personal are yours.', array('@num' => $num_private, '@num_personal' => $num_personal)) . '</div>';
-
-
-
-
- $query = db_select('node', 'n');
- $query->addExpression('COUNT(n.nid)', 'private_count');
- $query->addTag('node_access');
- $query->join('node_access_example', 'nae', 'nae.nid = n.nid');
- $num_private_accessible = $query->condition('nae.private', 1)->execute()->fetchField();
- $content .= '<div>' . t('You have access to @num private nodes.', array('@num' => $num_private_accessible)) . '</div>';
-
-
-
- $query = db_select('node', 'n', array('fetch' => PDO::FETCH_ASSOC));
- $query->addTag('node_access');
- $query->join('node_access_example', 'nae', 'nae.nid = n.nid');
- $query->join('users', 'u', 'u.uid = n.uid');
- $result = $query->fields('n', array('nid', 'title', 'uid'))
- ->fields('u', array('name'))
- ->condition('nae.private', 1)->execute();
-
- $rows = array();
- foreach ($result as $node) {
- $node['nid'] = l($node['nid'], 'node/' . $node['nid']);
- $rows[] = array('data' => $node, 'class' => array('accessible'));
- }
- $content .= '<div>' . t('Accessible rows:') .
- theme('table',
- array(
- 'header' => array('nid', 'title', 'uid', 'username'),
- 'rows' => $rows,
- )
- ) .
- '</div>';
-
- return array('#markup' => $content);
- }
-
- * Implements hook_permission().
- *
- * We create two permissions, which we can use as a base for our grant/deny
- * decision:
- *
- * - 'access any private content' allows global access to content marked
- * private by other users.
- * - 'edit any private content' allows global edit
- * privileges, basically overriding the node access system.
- *
- * Note that the 'edit any * content' and 'delete any * content' permissions
- * will allow edit or delete permissions to the holder, regardless of what
- * this module does.
- *
- * @see hook_permissions()
- */
- function node_access_example_permission() {
- return array(
- 'access any private content' => array(
- 'title' => t('Access any private content'),
- 'description' => t('May view posts of other users even though they are marked private.'),
- ),
- 'edit any private content' => array(
- 'title' => t('Edit any private content'),
- 'description' => t('May edit posts of other users even though they are marked private.'),
- ),
- );
- }
-
- * Implements hook_node_access().
- *
- * It allows view and edit access to private nodes, for the account whose
- * username is foobar.
- *
- * This hook is used to demonstrate how to give certain permissions to an
- * arbitrary user.
- */
- function node_access_example_node_access($node, $op, $account) {
-
-
- if (is_string($node)) {
- return NODE_ACCESS_IGNORE;
- }
- if (($op == 'view' || $op == 'update') && (!empty($account->name) && $account->name == 'foobar') && !empty($node->private)) {
- backdrop_set_message(t('Access to node @nid allowed because requester name (@name) is specifically allowed', array('@name' => $node->name, '@uid' => $account->uid)));
- return NODE_ACCESS_ALLOW;
- }
- return NODE_ACCESS_IGNORE;
- }
-
- * This is the constant for our node access grant ID, for the
- * node_access_example_view and node_access_example_edit realms. The ID could
- * be any integer, but we choose 23 because it is this author's favorite number.
- */
- define('NODE_ACCESS_EXAMPLE_GRANT_ALL', 23);
-
- * Implements hook_node_grants().
- *
- * It tells the node access system what grant IDs the user belongs to for each
- * realm, based on the operation being performed.
- *
- * When the user tries to perform an operation on the node, Backdrop calls
- * hook_node_grants() to determine grant ID and realm for the user. Backdrop
- * looks up the grant ID and realm for the node, and compares them to the
- * grant ID and realm provided here. If grant ID and realm match for both user
- * and node, then the operation is allowed.
- *
- * Grant ID and realm are both determined per node in
- * hook_node_access_records().
- *
- * In our example, we've created three access realms: one for authorship and two
- * that track with the permission system.
- *
- * We always add node_access_example_author to the list of grants, with a grant
- * ID equal to their user ID. We do this because in our model, authorship
- * always gives you permission to edit or delete your nodes, even if they're
- * marked private.
- *
- * Then we compare the user's permissions to the operation to determine whether
- * the user falls into the other two realms: node_access_example_view, and/or
- * node_access_example_edit. If the user has the 'access any private content'
- * permission we defined in hook_permission(), they're declared as belonging to
- * the node_access_example_realm. Similarly, if they have the 'edit any private
- * content' permission, we add the node_access_example_edit realm to the list
- * of grants they have.
- *
- * @see node_access_example_permission()
- * @see node_access_example_node_access_records()
- */
- function node_access_example_node_grants($account, $op) {
- $grants = array();
-
-
- if ($account->uid) {
- $grants['node_access_example_author'] = array($account->uid);
- }
-
-
-
- if ($op == 'view' && user_access('access any private content', $account)) {
- $grants['node_access_example_view'] = array(NODE_ACCESS_EXAMPLE_GRANT_ALL);
- }
-
- if (($op == 'update' || $op == 'delete') && user_access('edit any private content', $account)) {
- $grants['node_access_example_edit'] = array(NODE_ACCESS_EXAMPLE_GRANT_ALL);
- }
-
- return $grants;
- }
-
- * Implements hook_node_access_records().
- *
- * All node access modules must implement this hook. If the module is
- * interested in the privacy of the node passed in, return a list
- * of node access values for each grant ID we offer.
- *
- * In this example, for each node which is marked 'private,' we define
- * three realms:
- *
- * The first and second are realms are 'node_access_example_view' and
- * 'node_access_example_edit,' which have a single grant ID, 1. The
- * user is either a member of these realms or not, depending upon the
- * operation and the access permission set.
- *
- * The third is node_access_example_author. It gives the node
- * author special privileges. node_access_example_author has one grant ID for
- * every UID, and each user is automatically a member of the group where
- * GID == UID. This has the effect of giving each user their own grant ID
- * for nodes they authored, within this realm.
- *
- * Backdrop calls this hook when a node is saved, or when access permissions
- * change in order to rebuild the node access database table(s).
- *
- * The array you return will define the realm and the grant ID for the given
- * node. This is stored in the {node_access} table for subsequent comparison
- * against the user's realm and grant IDs, which you'll supply in
- * hook_node_grants().
- *
- * Realm names and grant IDs are arbitrary. Official backdrop naming conventions
- * do not cover access realms, but since all realms are stored in the same
- * database table, it's probably a good idea to use descriptive names which
- * follow the module name, such as mymodule_realmname.
- *
- * @see node_access_example_node_grants()
- */
- function node_access_example_node_access_records($node) {
-
-
- if (!empty($node->private)) {
- $grants = array();
- $grants[] = array(
- 'realm' => 'node_access_example_view',
- 'gid' => NODE_ACCESS_EXAMPLE_GRANT_ALL,
- 'grant_view' => 1,
- 'grant_update' => 0,
- 'grant_delete' => 0,
- 'priority' => 0,
- );
- $grants[] = array(
- 'realm' => 'node_access_example_edit',
- 'gid' => NODE_ACCESS_EXAMPLE_GRANT_ALL,
- 'grant_view' => 1,
- 'grant_update' => 1,
- 'grant_delete' => 1,
- 'priority' => 0,
- );
-
-
-
-
- if ($node->uid) {
- $grants[] = array(
- 'realm' => 'node_access_example_author',
- 'gid' => $node->uid,
- 'grant_view' => 1,
- 'grant_update' => 1,
- 'grant_delete' => 1,
- 'priority' => 0,
- );
- }
- return $grants;
- }
-
- }
-
- * Implements hook_form_alter().
- *
- * This module adds a simple checkbox to the node form labeled private. If the
- * checkbox is checked, only the node author and users with
- * 'access any private content' privileges may see it.
- */
- function node_access_example_form_alter(&$form, $form_state) {
- if (isset($form_state['build_info']['base_form_id']) && $form_state['build_info']['base_form_id'] == 'node_form') {
- $form['node_access_example'] = array(
- '#type' => 'fieldset',
- '#title' => t('Node Access Example'),
- '#collapsible' => TRUE,
- '#collapsed' => FALSE,
- '#weight' => 8,
- );
-
- $form['node_access_example']['private'] = array(
- '#type' => 'checkbox',
- '#title' => t('Private'),
- '#description' => t('Check here if this content should be set private and only shown to privileged users.'),
- '#default_value' => isset($form['#node']->private) ? $form['#node']->private : FALSE,
- );
- }
- }
-
- * Implements hook_node_load().
- *
- * Gather and add the private setting for the nodes Backdrop is loading.
- *
- * @see nodeapi_example.module
- */
- function node_access_example_node_load($nodes, $types) {
- $result = db_query('SELECT nid, private FROM {node_access_example} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes)));
- foreach ($result as $record) {
- $nodes[$record->nid]->private = $record->private;
- }
- }
-
- * Implements hook_node_delete().
- *
- * Delete the node_access_example record when the node is deleted.
- *
- * @see nodeapi_example.module
- */
- function node_access_example_node_delete($node) {
- db_delete('node_access_example')->condition('nid', $node->nid)->execute();
- }
-
- * Implements hook_node_insert().
- *
- * Insert a new access record when a node is created.
- *
- * @see nodeapi_example.module
- */
- function node_access_example_node_insert($node) {
- if (isset($node->private)) {
- db_insert('node_access_example')->fields(
- array(
- 'nid' => $node->nid,
- 'private' => (int) $node->private,
- )
- )->execute();
- }
- backdrop_set_message(t('New node @nid was created and private=@private', array('@nid' => $node->nid, '@private' => !empty($node->private) ? 1 : 0)));
- }
-
- * Implements hook_node_update().
- *
- * If the record in the node_access_example table already exists, we must
- * update it; if it doesn't exist, we create it.
- *
- * @see nodeapi_example.module
- */
- function node_access_example_node_update($node) {
-
- $exists = db_query('SELECT nid FROM {node_access_example} WHERE nid = :nid',
- array(':nid' => $node->nid))->fetchField();
-
- if ($exists) {
-
- $num_updated = db_update('node_access_example')
- ->fields(array(
- 'nid' => $node->nid,
- 'private' => !empty($node->private) ? 1 : 0,
- ))
- ->condition('nid', $node->nid)
- ->execute();
- backdrop_set_message(
- t("Updated node @nid to set private=@private (@num nodes actually updated)",
- array(
- '@private' => $node->private,
- '@num' => $num_updated,
- '@nid' => $node->nid,
- )
- )
- );
- }
- else {
-
- node_access_example_node_insert($node);
- backdrop_set_message(t('Inserted new node_access nid=@nid, private=@private', array('@nid' => $node->nid, '@private' => $node->private)));
- }
-
- }
-
- * @} End of "defgroup node_access_example".
- */