| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |