You are here

block_access.module in Block Access 6

Same filename and directory in other branches
  1. 8 block_access.module
  2. 6.2 block_access.module
  3. 7 block_access.module

File

block_access.module
View source
<?php

/* 
 * @file block_access.module
 * This module handles access permissions for the block admin page.
 * The block admin page is a beast in need of taming. This is one way
 * to tame it, but there must be something better.
 */

/*
 * Permission strings to pass to t()
 * The first bunch relate to all blocks so are plain strings
 * The second bunch use @block placeholder to hold the title of the block
 */
define('BLOCK_ACCESS_ADMIN', 'Administer block access settings');
define('BLOCK_ACCESS_CREATE', 'Create blocks');
define('BLOCK_ACCESS_ALL_VIEW', 'View all blocks');
define('BLOCK_ACCESS_ALL_MOVE', 'Move all blocks');
define('BLOCK_ACCESS_ALL_ENABLE', 'Enable all blocks');
define('BLOCK_ACCESS_ALL_DISABLE', 'Disable all blocks');
define('BLOCK_ACCESS_ALL_DELETE', 'Delete all blocks');
define('BLOCK_ACCESS_ALL_CONFIG', 'Configure all blocks.');
define('BLOCK_ACCESS_ALL_CONFIG_LANG', 'Configure all language settings');
define('BLOCK_ACCESS_ALL_CONFIG_SPEC', 'Configure all specific settings');
define('BLOCK_ACCESS_ALL_CONFIG_USER', 'Configure all user settings');
define('BLOCK_ACCESS_ALL_CONFIG_ROLE', 'Configure all role settings');
define('BLOCK_ACCESS_ALL_CONFIG_PAGE', 'Configure all page settings');

/*
 * Menu/Form items we need to mess with
 * The first is our own settings form, the others we are altering
 */
define('BLOCK_ACCESS_SETTINGS', 'admin/build/block/block-access');
define('BLOCK_ACCESS_MENU_ADD', 'admin/build/block/add');
define('BLOCK_ACCESS_MENU_DELETE', 'admin/build/block/delete');
define('BLOCK_ACCESS_MENU_CONFIG', 'admin/build/block/configure');
define('BLOCK_ACCESS_FORM_ADMIN', 'block_admin_display_form');
define('BLOCK_ACCESS_FORM_CONFIG', 'block_admin_configure');

/*
 * Implementation of hook_init()
 */
function block_access_init() {
  require_once drupal_get_path('module', 'block_access') . '/block_access.db.inc';
}

/* 
 * Implementation of hook_theme()
 */
function block_access_theme() {
  return array(
    'block_access_admin_list' => array(
      'arguments' => array(
        'form' => NULL,
      ),
      'file' => 'block_access.theme.inc',
    ),
  );
}

/* 
 * Implementation of hook_menu()
 */
function block_access_menu() {
  $items[BLOCK_ACCESS_SETTINGS] = array(
    'title' => 'Block Access Settings',
    'description' => 'Configure block access defaults',
    'access arguments' => array(
      BLOCK_ACCESS_ADMIN,
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'block_access_admin_list',
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'block_access.admin.inc',
  );
  $items[BLOCK_ACCESS_SETTINGS . '/edit'] = array(
    'title' => 'Block Access Settings',
    'description' => 'Configure block access defaults',
    'access arguments' => array(
      BLOCK_ACCESS_ADMIN,
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'block_access_module_form',
      5,
    ),
    'type' => MENU_CALLBACK,
    'file' => 'block_access.admin.inc',
  );
  return $items;
}

/*
 * Implementation of hook_menu_alter()
 * We need to override some core menu items to check permissions
 * @param $items array of menu items
 */
function block_access_menu_alter(&$items) {
  $items[BLOCK_ACCESS_MENU_ADD]['access arguments'] = array(
    BLOCK_ACCESS_CREATE,
  );
  $items[BLOCK_ACCESS_MENU_DELETE]['access callback'] = 'block_access_check_delete';
  $items[BLOCK_ACCESS_MENU_DELETE]['access arguments'] = array(
    4,
  );
  $items[BLOCK_ACCESS_MENU_CONFIG]['access callback'] = 'block_access_check_config';
  $items[BLOCK_ACCESS_MENU_CONFIG]['access arguments'] = array(
    4,
    5,
  );
}

/*
 *  Valid permissions for this module
 *  @return array An array of valid permissions for the block_access module
 */
function block_access_perm() {

  // All the "All blocks" level permissions
  $access = array(
    t(BLOCK_ACCESS_ADMIN),
    t(BLOCK_ACCESS_CREATE),
    t(BLOCK_ACCESS_ALL_VIEW),
    t(BLOCK_ACCESS_ALL_MOVE),
    t(BLOCK_ACCESS_ALL_ENABLE),
    t(BLOCK_ACCESS_ALL_DISABLE),
    t(BLOCK_ACCESS_ALL_CONFIG),
    t(BLOCK_ACCESS_ALL_DELETE),
    t(BLOCK_ACCESS_ALL_CONFIG_LANG),
    t(BLOCK_ACCESS_ALL_CONFIG_SPEC),
    t(BLOCK_ACCESS_ALL_CONFIG_USER),
    t(BLOCK_ACCESS_ALL_CONFIG_ROLE),
    t(BLOCK_ACCESS_ALL_CONFIG_PAGE),
  );
  return $access;
}

/*
 * Check if a user has access to a given permission
 * @param $module string - The module providing the block
 * @param $delta  string - The modules delta for this block
 * @param $perm   string - The permission we are checking
 * @return boolean - true if the user has access, false if they don't
 */
function block_access_user_access($module, $delta, $perm) {
  global $user;
  static $perms = array();
  if (!isset($perms[$module])) {
    $perms[$module] = array(
      $delta => array(),
    );
  }
  if (!isset($perms[$module][$delta])) {
    $perms[$module][$delta] = array();
  }
  if (!isset($perms[$module][$delta][$perm])) {
    $perms[$module][$delta][$perm] = false;
    foreach (block_access_get_roles($module, $perm, $delta) as $rid) {
      if (in_array($rid, array_keys($user->roles))) {
        $perms[$module][$delta][$perm] = true;
        break;
      }
    }
  }
  return $perms[$module][$delta][$perm];
}

/*
 * Helpers for each permission
 */
function block_access_can_view($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_VIEW)) || block_access_user_access($module, $delta, 'view');
}
function block_access_can_delete($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_DELETE)) || block_access_user_access($module, $delta, 'delete');
}
function block_access_can_enable($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_ENABLE)) || block_access_user_access($module, $delta, 'enable');
}
function block_access_can_disable($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_DISABLE)) || block_access_user_access($module, $delta, 'disable');
}
function block_access_can_move($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_MOVE)) || block_access_user_access($module, $delta, 'move');
}

// If any of the config perms are on, give access
function block_access_can_config($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_CONFIG)) || user_access(t(BLOCK_ACCESS_ALL_CONFIG_LANG)) || user_access(t(BLOCK_ACCESS_ALL_CONFIG_SPEC)) || user_access(t(BLOCK_ACCESS_ALL_CONFIG_USER)) || user_access(t(BLOCK_ACCESS_ALL_CONFIG_ROLE)) || user_access(t(BLOCK_ACCESS_ALL_CONFIG_PAGE)) || block_access_user_access($module, $delta, 'config') || block_access_user_access($module, $delta, 'config_lang') || block_access_user_access($module, $delta, 'config_spec') || block_access_user_access($module, $delta, 'config_user') || block_access_user_access($module, $delta, 'config_role') || block_access_user_access($module, $delta, 'config_page');
}
function block_access_can_config_lang($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_CONFIG_LANG)) || block_access_user_access($module, $delta, 'config_lang');
}
function block_access_can_config_spec($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_CONFIG_SPEC)) || block_access_user_access($module, $delta, 'config_spec');
}
function block_access_can_config_user($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_CONFIG_USER)) || block_access_user_access($module, $delta, 'config_user');
}
function block_access_can_config_role($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_CONFIG_ROLE)) || block_access_user_access($module, $delta, 'config_role');
}
function block_access_can_config_page($module, $delta) {
  return user_access(t(BLOCK_ACCESS_ALL_CONFIG_PAGE)) || block_access_user_access($module, $delta, 'config_page');
}

/* 
 * Separate out the permission checking for cleanliness
 * This one fiddles with the main block admin form
 * @param $form  array - the form API structure
 * @param $key   int   - key the relevant form item
 * @param $block array - the block data
 */
function block_access_check_perms(&$form, $key, $block) {
  $module = $block['module']['#value'];
  $delta = $block['delta']['#value'];

  // Remove the block completely if it's not allowed to be viewed
  if (!block_access_can_view($module, $delta)) {
    unset($form[$key]);
  }
  else {

    // Remove the delete link if the user can't delete this block
    if (!block_access_can_delete($module, $delta)) {
      unset($form[$key]['delete']);
    }

    // Remove the configure link if the user can't configure this block
    if (!block_access_can_config($module, $delta)) {
      unset($form[$key]['configure']);
    }

    // if a block is in BLOCK_REGION_NONE it is effectively disabled
    if ($block['region']['#default_value'] == BLOCK_REGION_NONE) {

      // Disable the region selection and weight if the user can't enable the block
      if (!block_access_can_enable($module, $delta)) {
        $form[$key]['region']['#disabled'] = TRUE;
        $form[$key]['weight']['#disabled'] = TRUE;
      }
    }
    else {

      // Disable the region selection and weight if the user can't move the block
      if (!block_access_can_move($module, $delta)) {
        $form[$key]['region']['#disabled'] = TRUE;
        $form[$key]['weight']['#disabled'] = TRUE;
      }

      // Remove the <none> option from the select list if the user can't disable the block
      if (!block_access_can_disable($module, $delta)) {
        unset($form[$key]['region']['#options'][BLOCK_REGION_NONE]);
      }
    }
  }
}

/*
 * This one fiddles with the block configuration form
 * simply removing each section if it's not allowed
 * @param $form array - the form API structure
 */
function block_access_check_config_form(&$form) {
  $module = $form['module']['#value'];
  $delta = $form['delta']['#value'];
  if (!block_access_can_config_lang($module, $delta)) {
    unset($form['i18n']);
  }
  if (!block_access_can_config_spec($module, $delta)) {
    unset($form['block_settings']);
  }
  if (!block_access_can_config_user($module, $delta)) {
    unset($form['user_vis_settings']);
  }
  if (!block_access_can_config_role($module, $delta)) {
    unset($form['role_vis_settings']);
    unset($form['role_view_settings']);
    unset($form['role_move_settings']);
    unset($form['role_enable_settings']);
    unset($form['role_disable_settings']);
    unset($form['role_delete_settings']);
    unset($form['role_config_settings']);
    unset($form['role_config_lang_settings']);
    unset($form['role_config_spec_settings']);
    unset($form['role_config_user_settings']);
    unset($form['role_config_role_settings']);
    unset($form['role_config_page_settings']);
  }
  if (!block_access_can_config_page($module, $delta)) {
    unset($form['page_vis_settings']);
  }
}

/*
 * Implementation of hook_form_alter
 */
function block_access_form_alter(&$form, &$form_state, $form_id) {

  // Only alter the form we're interested in
  if ($form_id == BLOCK_ACCESS_FORM_ADMIN) {

    // loop over all values, ignoring those that are not block arrays
    foreach ($form as $key => $block) {

      // it's a block array if it has the info attribute (assumption)
      if (is_array($block) && isset($block['info'])) {
        block_access_check_perms($form, $key, $block);
      }
    }

    // override the submit button to run perm validation before block.admin
    $form['#submit'][] = 'block_access_admin_display_submit';
  }
  elseif ($form_id == BLOCK_ACCESS_FORM_CONFIG) {
    $role_options = user_roles();
    $module = $form['module']['#value'];
    $delta = $form['delta']['#value'];

    // Add fieldset for each permission
    block_access_fieldset($form, $role_options, 'view', $module, $delta);
    block_access_fieldset($form, $role_options, 'move', $module, $delta);
    block_access_fieldset($form, $role_options, 'enable', $module, $delta);
    block_access_fieldset($form, $role_options, 'disable', $module, $delta);
    block_access_fieldset($form, $role_options, 'config', $module, $delta);
    block_access_fieldset($form, $role_options, 'delete', $module, $delta);
    block_access_fieldset($form, $role_options, 'config_lang', $module, $delta);
    block_access_fieldset($form, $role_options, 'config_spec', $module, $delta);
    block_access_fieldset($form, $role_options, 'config_user', $module, $delta);
    block_access_fieldset($form, $role_options, 'config_role', $module, $delta);
    block_access_fieldset($form, $role_options, 'config_page', $module, $delta);
    array_unshift($form['#submit'], 'block_access_config_presubmit');
    $form['#submit'][] = 'block_access_config_submit';
    $form['submit']['#weight'] = 99;
    block_access_check_config_form($form);
  }
}

/*
 * Helper to define fieldsets
 * @param $form         array  - The form API structure we're adding to
 * @param $role_options array  - The set of arrays to create checkboxes for
 * @param $perm         string - The permission we're adding a fieldset for
 * @param $module       string - The module providing the block
 * @param $delta        string - The delta of this block
 */
function block_access_fieldset(&$form, $role_options, $perm, $module, $delta = null) {
  $default_role_options = block_access_get_roles($module, $perm, $delta);
  $collapsed = empty($default_role_options) ? TRUE : FALSE;
  $form['role_' . $perm . '_settings'] = array(
    '#type' => 'fieldset',
    '#title' => t('Role specific ' . $perm . ' settings'),
    '#collapsible' => TRUE,
    '#collapsed' => $collapsed,
  );
  $form['role_' . $perm . '_settings'][$perm . '_roles'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Set permission for specific roles'),
    '#default_value' => $default_role_options,
    '#options' => $role_options,
    '#description' => t('Set this permission for the selected role(s). If no roles are set the option will be available to all.'),
  );
}

/*
 * Extra check on submit of the form so there's no cheating
 * @form  array  - The form API structure
 * @key   string - The key of the item we're interested in
 * @block array  - The block data
 */
function block_access_check_submit($form, $key, $block) {
  $valid = TRUE;
  $name = array(
    check_plain($block['info']),
  );

  // If the user is trying to disable the block but can't, report it
  if ($block['region'] == BLOCK_REGION_NONE && $form[$key]['region']['#value'] != BLOCK_REGION_NONE && !block_access_can_delete($block['module']['#value'], $block['delta']['#value'])) {
    drupal_set_message(t('You cannot disable @block.', $name));
    $valid = FALSE;
  }
  elseif ($block['region'] != BLOCK_REGION_NONE && $form[$key]['region']['#value'] == BLOCK_REGION_NONE && !block_access_can_enable($block['module']['#value'], $block['delta']['#value'])) {
    drupal_set_message(t('You cannot enable @block.', $name));
    $valid = FALSE;
  }
  elseif ($block['region'] != BLOCK_REGION_NONE && $form[$key]['region']['#value'] != BLOCK_REGION_NONE && $block['region'] != $form[$key]['region']['#value'] && !block_access_can_move($block['module']['#value'], $block['delta']['#value'])) {
    drupal_set_message(t('You cannot move @block.', $name));
    $valid = FALSE;
  }
  return $valid;
}

/*
 * Called on submit, before all other submit handlers to reset removed values
 */
function block_access_config_presubmit($form, &$form_state) {
  $module = $form_state['values']['module'];
  $delta = $form_state['values']['delta'];

  // restore existing values if they were removed from the form
  $edit = db_fetch_array(db_query("\n    SELECT pages, visibility, custom, title\n    FROM   {blocks}\n    WHERE  module = '%s'\n    AND delta = '%s'", $module, $delta));
  if (!isset($form_state['values']['pages'])) {
    $form_state['values']['pages'] = $edit['pages'];
  }
  if (!isset($form_state['values']['visibility'])) {
    $form_state['values']['visibility'] = $edit['visibility'];
  }
  if (!isset($form_state['values']['custom'])) {
    $form_state['values']['custom'] = $edit['custom'];
  }
  if (!isset($form_state['values']['title'])) {
    $form_state['values']['title'] = $edit['title'];
  }
  if (!isset($form_state['values']['roles'])) {
    $form_state['values']['roles'] = array();
    $result = db_query("\n      SELECT rid\n      FROM   {blocks_roles}\n      WHERE  module = '%s'\n      AND    delta = '%s'", $module, $delta);
    while ($role = db_fetch_object($result)) {
      $form_state['values']['roles'][] = $role->rid;
    }
  }

  // i18n deletes its config if the fields aren't in the form, so replace them here
  if (function_exists('i18nblocks_load')) {
    $i18n = i18nblocks_load($module, $delta);
    $form_state['values']['language'] = $i18n->language;
    $form_state['values']['ibid'] = $i18n->ibid;
  }
}

/*
 * Called on submit of the altered config form
 */
function block_access_config_submit($form, &$form_state) {
  $module = $form_state['values']['module'];
  $delta = $form_state['values']['delta'];
  if (isset($form_state['values']['view_roles'])) {
    block_access_config_set_roles('view', $form_state['values']['view_roles'], $module, $delta);
    block_access_config_set_roles('move', $form_state['values']['move_roles'], $module, $delta);
    block_access_config_set_roles('enable', $form_state['values']['enable_roles'], $module, $delta);
    block_access_config_set_roles('disable', $form_state['values']['disable_roles'], $module, $delta);
    block_access_config_set_roles('config', $form_state['values']['config_roles'], $module, $delta);
    block_access_config_set_roles('delete', $form_state['values']['delete_roles'], $module, $delta);
    block_access_config_set_roles('config_lang', $form_state['values']['config_lang_roles'], $module, $delta);
    block_access_config_set_roles('config_spec', $form_state['values']['config_spec_roles'], $module, $delta);
    block_access_config_set_roles('config_user', $form_state['values']['config_user_roles'], $module, $delta);
    block_access_config_set_roles('config_role', $form_state['values']['config_role_roles'], $module, $delta);
    block_access_config_set_roles('config_page', $form_state['values']['config_page_roles'], $module, $delta);
  }
}

/*
 * Set the roles for the given module/delta/perm combo
 * @param $perm    string  - The permission we're defining
 * @param $roleset array   - The set of roles being given access
 * @param $module  string  - The module providing the block
 * @param $delta   string  - The delta of the block
 */
function block_access_config_set_roles($perm, $roleset, $module, $delta = null) {
  $roles = array_filter($roleset);
  block_access_delete_roles($module, $perm, $delta);
  foreach ($roles as $rid) {
    block_access_add_role($rid, $module, $perm, $delta);
  }
}

/*
 * Called on submit of the altered admin form
 */
function block_access_admin_display_submit($form, &$form_state) {
  $valid = TRUE;

  // For each of the new values
  foreach ($form_state['values'] as $key => $block) {

    // Ignore non block values
    if (is_array($block) && isset($form[$key]['info'])) {
      if (!block_access_check_submit($form, $key, $block)) {
        $valid = FALSE;
      }
    }
  }
  if ($valid) {

    // Call the real and for true submit function
    block_admin_display_form_submit($form, $form_state);
  }
}

/*
 * Access checking functions, with differing arguments because the block
 * system is somewhat mystical
 */
function block_access_check_delete($bid) {
  $box = block_box_get($bid);
  return block_access_can_delete($box['module'], $box['delta']);
}
function block_access_check_config($module, $delta) {
  return block_access_can_config($module, $delta);
}