You are here

private_content.module in Private 8

Same filename and directory in other branches
  1. 8.2 private_content.module

A tremendously simple access control module -- it allows users to mark individual nodes as private; users with 'access private content' perms can read these nodes, while others cannot.

File

private_content.module
View source
<?php

/**
 * @file
 * A tremendously simple access control module -- it allows users to mark
 * individual nodes as private; users with 'access private content' perms can
 * read these nodes, while others cannot.
 */
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;
use Drupal\node\NodeTypeInterface;
define('PRIVATE_DISABLED', 0);
define('PRIVATE_ALLOWED', 1);
define('PRIVATE_AUTOMATIC', 2);
define('PRIVATE_ALWAYS', 3);
define('PRIVATE_GRANT_ALL', 1);

/**
 * Implements hook_enable().
 *
 * A node access module needs to force a rebuild of the node access table
 * when it is enabled to ensure that things are set up.
 */
function private_content_enable() {
  node_access_needs_rebuild(TRUE);
}

/**
 * Implements hook_disable().
 *
 * A node access module needs to force a rebuild of the node access table
 * when it is disabled to ensure that its entries are removed from the table.
 */
function private_content_disable() {
  private_content_disabling(TRUE);
  node_access_needs_rebuild(TRUE);
}

/**
 * Simple function to make sure we don't respond with grants when disabling
 * ourselves.
 */
function private_content_disabling($set = NULL) {
  static $disabling = FALSE;
  if ($set !== NULL) {
    $disabling = $set;
  }
  return $disabling;
}

/**
 * Implements hook_entity_base_field_info().
 */
function private_content_entity_base_field_info(EntityTypeInterface $entity_type) {
  $fields = array();
  if ($entity_type
    ->id() === 'node') {
    $fields['private'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Private'))
      ->setName('private')
      ->setRevisionable(TRUE)
      ->setDescription(t('Stores whether the node is marked private or not.'))
      ->setDefaultValue(FALSE)
      ->setDisplayConfigurable('view', TRUE);
  }
  return $fields;
}

/**
 * Implements hook_node_grants().
 */
function private_content_node_grants(AccountInterface $account, $op) {

  // First grant a grant to the author for own content.
  $grants['private_author'] = array(
    $account
      ->id(),
  );
  if ($op == 'view' && $account
    ->hasPermission('access private content')) {
    $grants['private_view'] = array(
      PRIVATE_GRANT_ALL,
    );
  }
  if (($op == 'update' || $op == 'delete') && $account
    ->hasPermission('edit private content')) {
    $grants['private_edit'] = array(
      PRIVATE_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.
 */
function private_content_node_access_records(NodeInterface $node) {
  if (private_content_disabling()) {
    return;
  }

  // We only care about the node if it's been marked private. If not, it is
  // treated just like any other node and we completely ignore it.
  if (isset($node->private) && $node->private->value == 1) {
    $grants = array();
    $grants[] = array(
      'realm' => 'private_view',
      'gid' => PRIVATE_GRANT_ALL,
      'grant_view' => 1,
      'grant_update' => 0,
      'grant_delete' => 0,
      'priority' => 0,
    );
    $grants[] = array(
      'realm' => 'private_edit',
      'gid' => PRIVATE_GRANT_ALL,
      'grant_view' => 1,
      'grant_update' => 1,
      'grant_delete' => 1,
      'priority' => 0,
    );
    $grants[] = array(
      'realm' => 'private_author',
      'gid' => $node
        ->getOwnerId(),
      'grant_view' => 1,
      'grant_update' => 1,
      'grant_delete' => 1,
      'priority' => 0,
    );
    return $grants;
  }
}

/**
 * Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm.
 *
 * This module adds a simple checkbox to the node form labeled private. If the
 * checkbox is labelled, only the node author and users with
 * 'access private content' privileges may see it.
 */
function private_content_form_node_form_alter(&$form, &$form_state) {

  /** @var \Drupal\Node\NodeInterface $node */
  $node = $form_state
    ->getFormObject()
    ->getEntity();

  /** @var \Drupal\node\NodeTypeInterface $node_type */
  $node_type = $node->type->entity;
  $default = $node_type
    ->getThirdPartySetting('private_content', 'private', PRIVATE_ALLOWED);
  if ($default != PRIVATE_DISABLED || !empty($node->private->value)) {
    if ($node
      ->isNew()) {
      $privacy = $default > PRIVATE_ALLOWED;
    }
    else {
      $privacy = isset($node->private) ? $node->private->value : 0;
    }
    if (\Drupal::currentUser()
      ->hasPermission('mark content as private') && $default != PRIVATE_ALWAYS) {
      if (\Drupal::currentUser()
        ->hasPermission('administer nodes')) {
        $form['options']['private'] = array(
          '#type' => 'checkbox',
          '#title' => t('Make this post private'),
          '#attributes' => array(
            'title' => t('When checked, only users with proper access permissions will be able to see this post.'),
          ),
          '#default_value' => $privacy,
        );
      }
      else {
        $form['private'] = array(
          '#type' => 'checkbox',
          '#title' => t('Make this post private'),
          '#attributes' => array(
            'title' => t('When checked, only users with proper access permissions will be able to see this post.'),
          ),
          '#default_value' => $privacy,
          '#weight' => 99,
        );
      }
    }
    else {
      $form['private'] = array(
        '#type' => 'value',
        '#value' => $privacy,
      );
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function private_content_form_node_type_form_alter(&$form, FormStateInterface $form_state) {

  /** @var \Drupal\node\NodeTypeInterface $type */
  $type = $form_state
    ->getFormObject()
    ->getEntity();
  $form['workflow']['private'] = array(
    '#type' => 'radios',
    '#title' => t('Privacy'),
    '#options' => array(
      PRIVATE_DISABLED => t('Disabled (always public)'),
      PRIVATE_ALLOWED => t('Enabled (public by default)'),
      PRIVATE_AUTOMATIC => t('Enabled (private by default)'),
      PRIVATE_ALWAYS => t('Hidden (always private)'),
    ),
    '#default_value' => $type
      ->getThirdPartySetting('private_content', 'private', PRIVATE_ALLOWED),
  );
  $form['#entity_builders'][] = 'private_content_form_node_type_form_builder';
}

/**
 * Entity builder for the node type form with private option.
 *
 * @see private_content_form_node_type_form_alter()
 */
function private_content_form_node_type_form_builder($entity_type, NodeTypeInterface $type, &$form, FormStateInterface $form_state) {
  $type
    ->setThirdPartySetting('private_content', 'private', $form_state
    ->getValue('private'));
}