diff options
Diffstat (limited to 'modules/node/node.module')
-rw-r--r-- | modules/node/node.module | 160 |
1 files changed, 144 insertions, 16 deletions
diff --git a/modules/node/node.module b/modules/node/node.module index 6b6f6c7f8..84c7da293 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -20,6 +20,17 @@ define('NODE_BUILD_PRINT', 5); * Implementation of hook_help(). */ function node_help($path, $arg) { + if ($path != 'admin/content/node-settings/rebuild' && strpos($path, '#') === FALSE + && user_access('access administration pages') && node_access_needs_rebuild()) { + if ($path == 'admin/content/node-settings') { + $message = t('The content access permissions need to be rebuilt.'); + } + else { + $message = t('The content access permissions need to be rebuilt. Please visit <a href="@node_access_rebuild">this page</a>.', array('@node_access_rebuild' => url('admin/content/node-settings/rebuild'))); + } + drupal_set_message($message, 'error'); + } + switch ($path) { case 'admin/help#node': $output = '<p>'. t('All content in a website is stored and treated as <b>nodes</b>. Therefore nodes are any postings such as blogs, stories, polls and forums. The node module manages these content types and is one of the strengths of Drupal over other content management systems.') .'</p>'; @@ -1309,6 +1320,9 @@ function node_menu() { 'title' => 'Rebuild permissions', 'page arguments' => array('node_configure_rebuild_confirm'), 'file' => 'node.admin.inc', + // Any user than can potentially trigger a node_acess_needs_rebuild(TRUE) + // has to be allowed access to the 'node access rebuild' confirm form. + 'access arguments' => array('access administration pages'), 'type' => MENU_CALLBACK, ); @@ -1999,7 +2013,7 @@ function node_db_rewrite_sql($query, $primary_table, $primary_field) { */ function node_access_acquire_grants($node) { $grants = module_invoke_all('node_access_records', $node); - if (!$grants) { + if (empty($grants)) { $grants[] = array('realm' => 'all', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0); } else { @@ -2061,33 +2075,147 @@ function node_access_write_grants($node, $grants, $realm = NULL, $delete = TRUE) } /** + * Flag / unflag the node access grants for rebuilding, or read the current + * value of the flag. + * + * When the flag is set, a message is displayed to users with 'access + * administration pages' permission, pointing to the 'rebuild' confirm form. + * This can be used as an alternative to direct node_access_rebuild calls, + * allowing administrators to decide when they want to perform the actual + * (possibly time consuming) rebuild. + * When unsure the current user is an adminisrator, node_access_rebuild + * should be used instead. + * + * @param $rebuild + * (Optional) The boolean value to be written. + * @return + * (If no value was provided for $rebuild) The current value of the flag. + */ +function node_access_needs_rebuild($rebuild = NULL) { + if (!isset($rebuild)) { + return variable_get('node_access_needs_rebuild', FALSE); + } + elseif ($rebuild) { + variable_set('node_access_needs_rebuild', TRUE); + } + else { + variable_del('node_access_needs_rebuild'); + } +} + +/** * Rebuild the node access database. This is occasionally needed by modules * that make system-wide changes to access levels. - */ -function node_access_rebuild() { + * + * When the rebuild is required by an admin-triggered action (e.g module + * settings form), calling node_access_needs_rebuild(TRUE) instead of + * node_access_rebuild() lets the user perform his changes and actually + * rebuild only once he is done. + * + * Note : As of Drupal 6, node access modules are not required to (and actually + * should not) call node_access_rebuild() in hook_enable/disable anymore. + * + * @see node_access_needs_rebuild + * + * @param $batch_mode + * Set to TRUE to process in 'batch' mode, spawning processing over several + * HTTP requests (thus avoiding the risk of PHP timeout if the site has a + * large number of nodes). + * hook_update_N and any form submit handler are safe contexts to use the + * 'batch mode'. Less decidable cases (such as calls from hook_user, + * hook_taxonomy, hook_node_type...) might consider using the non-batch mode. + */ +function node_access_rebuild($batch_mode = FALSE) { db_query("DELETE FROM {node_access}"); - // only recalculate if site is using a node_access module + // Only recalculate if the site is using a node_access module. if (count(module_implements('node_grants'))) { - // If not in 'safe mode', increase the maximum execution time: - if (!ini_get('safe_mode')) { - set_time_limit(240); - } - $result = db_query("SELECT nid FROM {node}"); - while ($node = db_fetch_object($result)) { - $loaded_node = node_load($node->nid, NULL, TRUE); - // To preserve database integrity, only aquire grants if the node - // loads successfully. - if (!empty($loaded_node)) { - node_access_acquire_grants($loaded_node); + if ($batch_mode) { + $batch = array( + 'title' => t('Rebuilding content access permissions'), + 'operations' => array( + array('_node_access_rebuild_batch_operation', array()), + ), + 'finished' => '_node_access_rebuild_batch_finished' + ); + batch_set($batch); + } + else { + // If not in 'safe mode', increase the maximum execution time. + if (!ini_get('safe_mode')) { + set_time_limit(240); + } + $result = db_query("SELECT nid FROM {node}"); + while ($node = db_fetch_object($result)) { + $loaded_node = node_load($node->nid, NULL, TRUE); + // To preserve database integrity, only aquire grants if the node + // loads successfully. + if (!empty($loaded_node)) { + node_access_acquire_grants($loaded_node); + } } } } else { - // not using any node_access modules. add the default grant. + // Not using any node_access modules. Add the default grant. db_query("INSERT INTO {node_access} VALUES (0, 0, 'all', 1, 0, 0)"); } + + if (!isset($batch)) { + drupal_set_message(t('The node access table has been rebuilt.')); + node_access_needs_rebuild(FALSE); + cache_clear_all(); + } +} + +/** + * Batch operation for node_access_rebuild_batch. + * + * This is a mutlistep operation : we go through all nodes by packs of 20. + * The batch processing engine interrupts processing and sends progress + * feedback after 1 second execution time. + */ +function _node_access_rebuild_batch_operation(&$context) { + if (empty($context['sandbox'])) { + // Initiate multistep processing. + $context['sandbox']['progress'] = 0; + $context['sandbox']['current_node'] = 0; + $context['sandbox']['max'] = db_result(db_query('SELECT COUNT(DISTINCT nid) FROM {node}')); + } + + // Process the next 20 nodes. + $limit = 20; + $result = db_query_range("SELECT nid FROM {node} WHERE nid > %d ORDER BY nid ASC", $context['sandbox']['current_node'], 0, $limit); + while ($row = db_fetch_array($result)) { + $loaded_node = node_load($row['nid'], NULL, TRUE); + // To preserve database integrity, only aquire grants if the node + // loads successfully. + if (!empty($loaded_node)) { + node_access_acquire_grants($loaded_node); + } + $context['sandbox']['progress']++; + $context['sandbox']['current_node'] = $loaded_node->nid; + } + + // Multistep processing : report progress. + if ($context['sandbox']['progress'] != $context['sandbox']['max']) { + $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max']; + } +} + +/** + * Post-processing for node_access_rebuild_batch. + */ +function _node_access_rebuild_batch_finished($success, $results, $operations) { + if ($success) { + drupal_set_message(t('The content access permissions have been rebuilt.')); + node_access_needs_rebuild(FALSE); + } + else { + drupal_set_message(t('The content access permissions have not been properly rebuilt.'), 'error'); + } cache_clear_all(); } + /** * @} End of "defgroup node_access". */ |