[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/content_access/ -> content_access.module (source)

   1  <?php
   2  // $Id: content_access.module,v 1.1.2.9.2.19 2009/07/31 09:46:36 fago Exp $
   3  
   4  /**
   5   * @file Content access module file.
   6   */
   7  
   8  
   9  /**
  10   * Implementation of hook_menu().
  11   */
  12  function content_access_menu() {
  13    $items = array();
  14  
  15    $items['node/%node/access'] = array(
  16      'title' => 'Access control',
  17      'page callback' => 'drupal_get_form',
  18      'page arguments' => array('content_access_page', 1),
  19      'access callback' => 'content_access_node_page_access',
  20      'access arguments' => array(1),
  21      'file' => 'content_access.admin.inc',
  22      'weight' => 3,
  23      'type' => MENU_LOCAL_TASK
  24    );
  25  
  26    foreach (node_get_types('types', NULL, TRUE) as $type) {
  27      $type_url_str = str_replace('_', '-', $type->type);
  28      $items['admin/content/node-type/'. $type_url_str .'/access'] = array(
  29        'title' => t('Access control'),
  30        'description' => t('Configure content access control.'),
  31        'page callback' => 'drupal_get_form',
  32        'page arguments' => array('content_access_admin_settings', $type->type),
  33        'access callback' => 'content_access_admin_settings_access',
  34        'access arguments' => array(),
  35        'type' => MENU_LOCAL_TASK,
  36        'file' => 'content_access.admin.inc',
  37        'weight' => 1,
  38      );
  39    }
  40    return $items;
  41  }
  42  
  43  function content_access_node_page_access($node) {
  44    global $user;
  45    return content_access_get_settings('per_node', $node->type) && user_access('grant content access') || content_access_get_settings('per_node', $node->type) && (user_access('grant own content access') && ($user->uid == $node->uid));
  46  }
  47  
  48  function content_access_admin_settings_access() {
  49    return user_access('administer nodes') && user_access('administer content types');
  50  }
  51  
  52  /**
  53   * Implementation of hook_perm().
  54   */
  55  function content_access_perm() {
  56    return array('grant content access', 'grant own content access');
  57  }
  58  
  59  /**
  60   * Implementation of hook_node_grants().
  61   */
  62  function content_access_node_grants($account, $op) {
  63    return array(
  64      'content_access_author' => array($account->uid),
  65      'content_access_rid' => array_keys($account->roles),
  66    );
  67  }
  68  
  69  /**
  70   * Implementation of hook_node_access_records()
  71   */
  72  function content_access_node_access_records($node) {
  73    if (content_access_disabling()) {
  74      return;
  75    }
  76  
  77    // Apply per node settings if necessary.
  78    if (content_access_get_settings('per_node', $node->type)) {
  79      $grants = array();
  80      foreach (array('view', 'update', 'delete') as $op) {
  81        foreach (content_access_get_rids_per_node_op($op, $node) as $rid) {
  82          $grants[$rid]['grant_'. $op] = 1;
  83        }
  84      }
  85      foreach ($grants as $rid => $grant) {
  86        $grants[$rid] = content_access_proccess_grant($grant, $rid, $node);
  87      }
  88      // Care for the author grant.
  89      $grant = array();
  90      foreach (array('view', 'update', 'delete') as $op) {
  91        // Get all roles that have access to use $op on this node.
  92        $any_roles = drupal_map_assoc(content_access_per_node_setting($op, $node));
  93        $any_roles += ($op != 'view') ? content_access_get_settings($op, $node->type) : array();
  94        $grant['grant_'. $op] = content_access_own_op($node, $any_roles, content_access_get_rids_per_node_op($op .'_own', $node));
  95      }
  96  
  97      if (array_filter($grant)) {
  98        $grant['realm'] = 'content_access_author';
  99        $grants[] = content_access_proccess_grant($grant, $node->uid, $node);
 100      }
 101    }
 102    else {
 103      // Apply the content type defaults.
 104      $grants = content_access_get_type_grant($node);
 105    }
 106  
 107    if (empty($grants)) {
 108      // This means we grant no access.
 109      $grants[] = content_access_proccess_grant(array(), 0, $node);
 110    }
 111    else {
 112      content_access_optimize_grants($grants, $node);
 113    }
 114    return $grants;
 115  }
 116  
 117  /**
 118   * Implementation of hook_nodeapi().
 119   */
 120  function content_access_nodeapi($node, $op, $teaser, $page) {
 121    if ($op == 'delete') {
 122      db_query("DELETE FROM {content_access} WHERE nid = %d", $node->nid);
 123    }
 124  }
 125  
 126  /**
 127   * Used by the ACL module.
 128   */
 129  function content_access_enabled() {
 130    return !content_access_disabling();
 131  }
 132  
 133  /**
 134   * Implementation of hook_disable().
 135   */
 136  function content_access_disable() {
 137    content_access_disabling(TRUE);
 138  }
 139  
 140  /**
 141   * Remembers if we have disabled access.
 142   */
 143  function content_access_disabling($set = NULL) {
 144    static $disabling = FALSE;
 145  
 146    if (isset($set)) {
 147      $disabling = $set;
 148    }
 149    return $disabling;
 150  }
 151  
 152  /**
 153   * Returns the content_access' settings.
 154   *
 155   * @param $return
 156   *   One of the content_access_available_settings(), e.g. 'view' or 'per_node'.
 157   * @param $type
 158   *   If not all, return the setting for the specified type.
 159   */
 160  function content_access_get_settings($return = 'all', $type = NULL) {
 161    if ($return == 'all') {
 162      return variable_get('content_access_settings', array());
 163    }
 164    if (isset($type)) {
 165      $settings = content_access_get_settings($return);
 166      return isset($settings[$type]) ? $settings[$type] : content_access_get_setting_defaults($return, $type);
 167    }
 168    if (!isset($type)) {
 169      $settings = content_access_get_settings();
 170      return isset($settings[$return]) ? $settings[$return] : array();
 171    }
 172    return array();
 173  }
 174  
 175  /**
 176   * Saves the content_access settings - needs the complete settings array.
 177   */
 178  function content_access_set_settings($settings) {
 179    // Cleanup the settings before saving.
 180    foreach (content_access_available_settings() as $setting) {
 181      if (isset($settings[$setting])) {
 182        foreach ($settings[$setting] as $type => $value) {
 183          if (!isset($value)) {
 184            unset($settings[$setting][$type]);
 185          }
 186        }
 187      }
 188    }
 189    variable_set('content_access_settings', $settings);
 190  }
 191  
 192  /*
 193   * Return an array containing all available content_access settings.
 194   */
 195  function content_access_available_settings() {
 196    return array('view', 'update', 'delete', 'view_own', 'update_own', 'delete_own', 'per_node', 'priority');
 197  }
 198  
 199  /**
 200   * Defines default values for settings.
 201   */
 202  function content_access_get_setting_defaults($setting, $type) {
 203    switch ($setting) {
 204      default:
 205        return array();
 206      case 'view':
 207      case 'view_own':
 208        return array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID);
 209      case 'update':
 210      case 'update_own':
 211      case 'delete':
 212      case 'delete_own':
 213        return content_access_get_permission_access(content_access_get_permission_by_op($setting, $type));
 214      case 'priority':
 215        return 0;
 216    }
 217  }
 218  
 219  /**
 220   * Returns an array of role ids, that contain the given permission.
 221   */
 222  function content_access_get_permission_access($perm, $reset = FALSE) {
 223    static $roles = array();
 224  
 225    if ($reset) {
 226      $roles = array();
 227    }
 228    if (!isset($roles[$perm]) && $perm) {
 229      $roles[$perm] = array_keys(user_roles(0, $perm));
 230    }
 231    return isset($roles[$perm]) ? $roles[$perm] : array();
 232  }
 233  
 234  /**
 235   * Gets the name of a permission for the given operation, if there is a suiting one.
 236   */
 237  function content_access_get_permission_by_op($op, $type) {
 238    switch ($op) {
 239      default:
 240        return FALSE;
 241      case 'update':
 242        return 'edit any '. $type .' content';
 243      case 'update_own':
 244        return 'edit own '. $type .' content';
 245      case 'delete':
 246        return 'delete any '. $type .' content';
 247      case 'delete_own':
 248        return 'delete own '. $type .' content';
 249    }
 250  }
 251  
 252  /**
 253   * Returns the default grants for a given node type.
 254   */
 255  function content_access_get_type_grant($node) {
 256    // Cache per type default grants in a static array
 257    static $defaults = array();
 258  
 259    if (!isset($defaults[$node->type])) {
 260      $grants = array();
 261  
 262      // Only process the 'view' op as node_access() will take care of edit and delete
 263      foreach (content_access_get_settings('view', $node->type) as $rid) {
 264        $grants[$rid]['grant_view'] = 1;
 265        $grants[$rid] = content_access_proccess_grant($grants[$rid], $rid, $node);
 266      }
 267      $defaults[$node->type] = $grants;
 268    }
 269  
 270    // Care for the author grant.
 271    $grant = $grants = array();
 272    $grant['grant_view'] = content_access_own_op($node, content_access_get_settings('view', $node->type), content_access_get_settings('view_own', $node->type));
 273    if ($grant['grant_view']) {
 274      $grant['realm'] = 'content_access_author';
 275      $grants = array('author' => content_access_proccess_grant($grant, $node->uid, $node));
 276    }
 277  
 278    return $defaults[$node->type] + $grants;
 279  }
 280  
 281  /**
 282   * Process a grant, which means add priority, realm and other properties.
 283   */
 284  function content_access_proccess_grant($grant, $gid, $node) {
 285    $grant += array('grant_view' => 0, 'grant_update' => 0, 'grant_delete' => 0, 'realm' => 'content_access_rid');
 286    $grant['gid'] = $gid;
 287    $grant['priority'] = content_access_get_settings('priority', $node->type);
 288    return $grant;
 289  }
 290  
 291  /**
 292   * Determines the grant for the node author and the given allowed roles of a operation.
 293   *
 294   * @param $any_roles
 295   *   The roles with which anybody has access (not optimized!)
 296   * @param $own_roles
 297   *   The roles with which only the author has acess (optimized!)
 298   */
 299  function content_access_own_op($node, $any_roles, $own_roles) {
 300    static $roles = array();
 301  
 302    if (!isset($roles[$node->uid])) {
 303      $roles[$node->uid] = $node->uid ? array(DRUPAL_AUTHENTICATED_RID) : array(DRUPAL_ANONYMOUS_RID);
 304      $result = db_query('SELECT rid FROM {users_roles} WHERE uid = %d', $node->uid);
 305      while ($role = db_fetch_object($result)) {
 306        $roles[$node->uid][] = $role->rid;
 307      }
 308    }
 309    if (array_intersect($roles[$node->uid], $any_roles)) {
 310      // If there is access due to "any permissions" there is no need to at an author grant.
 311      return 0;
 312    }
 313    return array_intersect($roles[$node->uid], $own_roles) ? 1 : 0;
 314  }
 315  
 316  /**
 317   * Returns optimized role ids for the given operation and node to
 318   * grant access for.
 319   *
 320   * If to a role access is granted by permissions, it's not necessary
 321   * to write a grant for it. So it won't be returned.
 322   *
 323   * @param $op
 324   *   One of the supported operations.
 325   * @param $node
 326   *   The node object.
 327   */
 328  function content_access_get_rids_per_node_op($op, $node) {
 329    $rids = content_access_per_node_setting($op, $node);
 330    if ($permission = content_access_get_permission_by_op($op, $node->type)) {
 331      $perm_roles = content_access_get_permission_access($permission);
 332      $rids = array_diff($rids, $perm_roles);
 333      if (in_array(DRUPAL_AUTHENTICATED_RID, $perm_roles)) {
 334        return in_array(DRUPAL_ANONYMOUS_RID, $rids) ? array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID) : array(DRUPAL_AUTHENTICATED_RID);
 335      }
 336    }
 337    return $rids;
 338  }
 339  
 340  
 341  /**
 342   * Returns the per node role settings. If no per node settings are available,
 343   * it will return the content type settings.
 344   *
 345   * @param $op
 346   *   One of the supported operations.
 347   * @param $node
 348   *   The node object.
 349   * @param $settings
 350   *    Optional array used to update the settings cache with the given settings.
 351   * @return
 352   *   An array of role ids which have access.
 353   */
 354  function content_access_per_node_setting($op, $node, $settings = NULL) {
 355    static $grants = array();
 356  
 357    if (isset($settings)) {
 358      // Update settings cache
 359      $grants[$node->nid] = $settings;
 360      return;
 361    }
 362    if (!isset($grants[$node->nid]) || $grants[$node->nid] === FALSE) {
 363      $grants[$node->nid] = content_access_get_per_node_settings($node);
 364    }
 365    // Return the content type defaults if no per node settings are available
 366    return isset($grants[$node->nid][$op]) ? $grants[$node->nid][$op] : content_access_get_settings($op, $node->type);
 367  }
 368  
 369  /**
 370   * Saves custom per node settings in the own content_access table.
 371   */
 372  function content_access_save_per_node_settings($node, $settings) {
 373    db_query("UPDATE {content_access} SET settings = '%s' WHERE nid = %d", serialize($settings), $node->nid);
 374    if (!db_affected_rows()) {
 375      db_query("INSERT INTO {content_access} (nid, settings) VALUES(%d, '%s')", $node->nid, serialize($settings));
 376    }
 377    // Make content_access_per_node_setting() use the new settings
 378    content_access_per_node_setting(NULL, $node, $settings);
 379  }
 380  
 381  /**
 382   * Deletes all custom per node settings, so that content type defaults are used again.
 383   */
 384  function content_access_delete_per_node_settings($node) {
 385    db_query("DELETE FROM {content_access} WHERE nid = %d", $node->nid);
 386    // Clear the cache.
 387    content_access_per_node_setting(NULL, $node, FALSE);
 388    // Delete possible acl settings
 389    if (module_exists('acl')) {
 390      foreach (array('view', 'update', 'delete') as $op) {
 391        $acl_id = content_access_get_acl_id($node, $op);
 392        acl_delete_acl($acl_id);
 393      }
 394    }
 395  }
 396  
 397  /**
 398   * Gets the per node settings of a node.
 399   *
 400   * @note
 401   *   This function won't apply defaults, so if there are no other settings
 402   *   it will return an empty array.
 403   */
 404  function content_access_get_per_node_settings($node) {
 405    $settings = db_result(db_query("SELECT settings FROM {content_access} WHERE nid = %d", $node->nid));
 406    if (!$settings) {
 407      return array();
 408    }
 409    return unserialize($settings);
 410  }
 411  
 412  /**
 413   * Removes grants that doesn't change anything.
 414   *
 415   * @note
 416   *   The grants are compared with the normal access control settings.
 417   */
 418  function content_access_optimize_grants(&$grants, $node) {
 419    $rids = array('view' => array(), 'update' => array(), 'delete' => array());
 420    foreach ($grants as $key => $grant) {
 421      foreach (array('view', 'update', 'delete') as $op) {
 422        if (is_numeric($key) && !empty($grant['grant_'. $op])) {
 423          $rids[$op][] = $key;
 424        }
 425      }
 426    }
 427    // Detect if all are allowed to view
 428    $all = array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID);
 429    if (count(array_diff($all, $rids['view'])) == 0) {
 430      //grant view access to all instead of single roles
 431      $rids['view'] = array('all');
 432      $grants['all'] = array('realm' => 'all', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0, 'priority' => content_access_get_settings('priority', $node->type));
 433    }
 434    // If authenticated users are involved, remove unnecessary other roles.
 435    foreach (array('view', 'update', 'delete') as $op) {
 436      if (in_array(DRUPAL_AUTHENTICATED_RID, $rids[$op])) {
 437        $rids[$op] = in_array(DRUPAL_ANONYMOUS_RID, $rids[$op]) ? array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID) : array(DRUPAL_AUTHENTICATED_RID);
 438      }
 439    }
 440  
 441    // Now let's remove unnecessary grants, if any.
 442    foreach ($grants as $key => $grant) {
 443      if (!is_numeric($key)) {
 444        continue;
 445      }
 446      foreach (array('view', 'update', 'delete') as $op) {
 447        if ($grant['grant_'. $op] && in_array($key, $rids[$op])) {
 448          //it's still here, so we can't remove this grant
 449          continue 2;
 450        }
 451      }
 452      //ok, remove it
 453      unset($grants[$key]);
 454    }
 455  }
 456  
 457  /**
 458   * Implementation of hook_node_type():
 459   * Update settings on node type name change.
 460   */
 461  function content_access_node_type($op, $info) {
 462    switch ($op) {
 463      case 'delete':
 464        $settings = content_access_get_settings();
 465        foreach (content_access_available_settings() as $setting) {
 466          unset($settings[$setting][$info->type]);
 467        }
 468        content_access_set_settings($settings);
 469        break;
 470      case 'update':
 471        if (!empty($info->old_type) && $info->old_type != $info->type) {
 472          $settings = content_access_get_settings();
 473          foreach (content_access_available_settings() as $setting) {
 474            $settings[$setting][$info->type] = $settings[$setting][$info->old_type];
 475            unset($settings[$setting][$info->old_type]);
 476          }
 477          content_access_set_settings($settings);
 478        }
 479        break;
 480    }
 481  }
 482  
 483  /**
 484   * Implementation of hook_node_access_explain().
 485   */
 486  function content_access_node_access_explain($row) {
 487    static $roles;
 488  
 489    if (!isset($roles)) {
 490      $roles = user_roles();
 491    }
 492    if (!$row->gid && $row->realm == 'content_access_rid') {
 493      return t('Content access: No access is granted.');
 494    }
 495    switch ($row->realm) {
 496      case 'content_access_author':
 497        return t('Content access: author of the content can access');
 498      case 'content_access_rid':
 499        return t('Content access: %role can access', array('%role' => $roles[$row->gid]));
 500    }
 501  }
 502  
 503  /**
 504   * Implementation of hook_form_alter().
 505   */
 506  function content_access_form_alter(&$form, $form_state, $form_id) {
 507    if ($form_id == 'user_admin_perm') {
 508      module_load_include('inc', 'content_access', 'content_access.admin');
 509      $form['#submit'][] = 'content_access_user_admin_perm_submit';
 510    }
 511  }
 512  
 513  /**
 514   * Returns an array of operations used by the module.
 515   */
 516  function _content_access_get_operations() {
 517    return array('view', 'view_own', 'update', 'update_own', 'delete', 'delete_own');
 518  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7