#156778 by asimmonds: revert node and comment deletions to the pre-deletion API state

6.x
Gábor Hojtsy 2007-07-13 20:04:47 +00:00
parent dfb1af8935
commit 51b789c0d3
3 changed files with 55 additions and 375 deletions

View File

@ -2802,243 +2802,6 @@ function drupal_common_themes() {
);
}
/**
* Create/build/execute deletion packages.
*
* Note that this function should not be called directly, but through the following helper functions:
*
* drupal_delete_initiate()
* drupal_delete_add_query()
* drupal_delete_confirm()
* drupal_delete_execute()
* drupal_delete_add_callback()
* drupal_delete_add_metadata()
* drupal_delete_add_form_elements()
*
* @param $op
* An operation to be performed.
*
* @param $id
* A unique string identifier for the deletion being performed.
*/
function _drupal_delete($op, $id = '') {
static $delete_type = NULL,
$delete_id = NULL,
$deletion_data = array(),
$built = NULL,
$form = array();
$confirm = NULL;
$execute = NULL;
// Process additional arguments.
$all_args = func_get_args();
if (count($all_args) > 2) {
// Get any additional arguments.
$args = array_slice($all_args, 2);
// Shift off query string if present.
if ($op == 'query') {
$query = array_shift($args);
}
// Clean up args passed as an array.
if (is_array($args[0])) {
$args = $args[0];
}
}
else {
$args = array();
}
switch ($op) {
// Query to add to a package
case 'query':
// Add the information for this deletion into the package array.
$deletion_data[$delete_type][$delete_id]['queries'][] = array('query' => $query, 'args' => $args);
break;
// New package -- mark it as such and get the next deletion ID.
case 'new package':
$delete_type = $id['type'];
$delete_id = $id['id'];
$deletion_data[$delete_type][$delete_id] = array(
'metadata' => array(),
'callback' => array(),
'form' => array(),
);
break;
// Confirm all packages.
case 'confirm':
// Set execute switch and destination if bypass is enabled.
if (variable_get('bypass_delete_confirmation', 0)) {
$execute = TRUE;
$destination = isset($args['destination']) ? $args['destination'] : NULL;
}
else {
$confirm = TRUE;
}
break;
// Add package-specific form array pieces, callbacks, metadata.
case 'form':
case 'callback':
case 'metadata':
$deletion_data[$delete_type][$delete_id][$op] += $args;
break;
// Execute all packages.
case 'execute':
$execute = TRUE;
$destination = $args['destination'];
break;
}
// Allow modules to inject confirm/abort data.
if (isset($confirm) || isset($execute)) {
// $built is kept as a static and checked to avoid calling this code twice
// when the package is executed.
if (!isset($built)) {
$built = TRUE;
// Main confirm form.
if (isset($args['form'])) {
$form = $args['form'];
}
$count = 0;
foreach ($deletion_data as $type => $deletion_info) {
// Reset $delete_type to the type being checked.
$delete_type = $type;
foreach ($deletion_info as $package_id => $package_info) {
$package_confirm_data = array();
// Reset $delete_id to the package to be passed.
$delete_id = $package_id;
// Call hook_delete_pre() once for each package.
foreach (module_implements('delete_pre') as $module) {
$confirm_data = module_invoke($module, 'delete_pre', $type, $package_id, $package_info);
// Check for an aborted package.
if (isset($confirm_data['abort'])) {
// Set abort message.
if (isset($confirm_data['abort']['message'])) {
drupal_set_message($confirm_data['abort']['message'], 'error');
}
// Set abort destination.
if (isset($confirm_data['abort']['destination'])) {
$abort_destination = $confirm_data['abort']['destination'];
}
// Remove the package.
unset($deletion_data[$type][$package_id]);
}
else {
// Add elements to confirm form data for the package.
$package_confirm_data = array_merge_recursive($package_confirm_data, $confirm_data);
}
}
// Add in package-specific confirm form elements if the package still exists.
if (isset($deletion_data[$type][$package_id])) {
$form = array_merge_recursive($form, $package_confirm_data);
if (!empty($package_info['form'])) {
$form = array_merge_recursive($form, $package_info['form']);
}
// If queries exist, then add to the count of executable packages.
if (isset($package_info['queries'])) {
$count++;
}
}
}
}
if (isset($confirm)) {
// Generate the confirm form if any packages remain.
if ($count) {
$question = isset($args['question']) ? $args['question'] : t('Delete the item?');
$path = isset($args['path']) ? $args['path'] : 'node';
unset($args['question'], $args['path']);
$args['name'] = 'delete';
// Submit handler - triggers execute operation for the API.
$form['#submit'] = array('delete_confirm_submit');
return confirm_form($form, $question, $path, $args);
}
// No packages left after aborts -- go to an abort destination if it exists.
elseif (isset($abort_destination)) {
drupal_goto($abort_destination);
}
// Fallback to cancel path.
elseif (isset($args['path'])) {
drupal_goto($args['path']);
}
// Last fallback, front page.
else {
drupal_goto('<front>');
}
}
}
}
// Execute all constructed packages.
if (isset($execute)) {
// Explicitly reset the package information.
$delete_type = NULL;
$delete_id = NULL;
$package_data = $deletion_data;
$deletion_data = array();
$built = NULL;
// Execute the deletion of all packages.
_drupal_delete_execute($package_data, $destination);
}
}
/**
* Executes all database deletions in all packages of a single page call.
*
* @param $package_data
* The complete array of deletion data for all packages.
* @param $destination
* A destination for operations that bypass the confirm step.
*/
function _drupal_delete_execute($package_data, $destination = NULL) {
foreach ($package_data as $type => $package) {
foreach ($package as $package_id => $package_info) {
// Allow modules to perform any operations just prior to the deletion of the package.
drupal_alter('delete', $type, $package_id, $package_info);
// Perform the deletions.
if (isset($package_info['queries'])) {
foreach ($package_info['queries'] as $deletion) {
db_query($deletion['query'], $deletion['args']);
}
}
// Execute post-deletion callbacks.
foreach ($package_info['callback'] as $function => $args) {
if (function_exists($function)) {
call_user_func_array($function, $args);
}
}
}
}
// Redirect for confirmation bypass.
drupal_redirect($destination);
}
/**
* Generates a drupal_goto() based on the value of $goto.
*
* @param $goto
* Can be any of the following values:
* - A string representing a valid Drupal path.
* - An array containing arguments to pass to drupal_goto().
* - NULL to redirect to $_GET['q'].
* - FALSE to bypass the redirection.
*/
function drupal_redirect($goto) {
if ($goto !== FALSE) {
if (isset($goto)) {
if (is_array($goto)) {
call_user_func_array('drupal_goto', $goto);
}
else {
drupal_goto($goto);
}
}
drupal_goto($_GET['q']);
}
}
/**
* @ingroup schemaapi
* @{

View File

@ -1284,78 +1284,45 @@ function theme_comment_admin_overview($form) {
function comment_multiple_delete_confirm(&$form_state) {
$edit = $form_state['post'];
$form['comments']['#tree'] = TRUE;
$form['prefix'] = array('#value' => '<ul>');
$form['comments'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
// array_filter() returns only elements with actual values
$comment_counter = 0;
foreach (array_filter($edit['comments']) as $cid) {
foreach (array_filter($edit['comments']) as $cid => $value) {
$comment = _comment_load($cid);
if (is_object($comment) && is_numeric($comment->cid)) {
$subject = db_result(db_query('SELECT subject FROM {comments} WHERE cid = %d', $cid));
// This is a placeholder -- preserves proper ordering in the confirm form.
$form["comment_$cid"] = array();
// Start a new package for each comment.
drupal_delete_initiate('comment', $comment->cid);
drupal_delete_add_callback(array('comment_delete_post' => array($comment)));
_comment_delete_thread($comment);
// Add the confirm form piece for this comment.
drupal_delete_add_form_elements(
array(
"comment_$cid" => array(
'#value' => check_plain($subject),
'#prefix' => '<li>',
'#suffix' => "</li>\n",
),
'comments' => array(
"comment_$cid" => array(
'#type' => 'hidden',
'#value' => $cid,
)
)
)
);
$form['comments'][$cid] = array('#type' => 'hidden', '#value' => $cid, '#prefix' => '<li>', '#suffix' => check_plain($subject) .'</li>');
$comment_counter++;
}
}
$form['suffix'] = array('#value' => '</ul>');
$form['operation'] = array(
'#type' => 'hidden',
'#value' => 'delete'
);
// New package for the main admin callback.
drupal_delete_initiate('comment', 'admin');
// Add the main callback for the mass deletion last.
drupal_delete_add_callback(array('comment_multiple_delete_confirm_post' => array()));
$form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
if (!$comment_counter) {
drupal_set_message(t('There do not appear to be any comments to delete or your selected comment was deleted by another administrator.'));
drupal_goto('admin/content/comment');
}
else {
return drupal_delete_confirm(
array(
'form' => $form,
'question' => t('Are you sure you want to delete these comments and all their children?'),
'path' => 'admin/content/comment',
'yes' => t('Delete all'),
'destination' => 'admin/content/comment',
)
);
return confirm_form($form,
t('Are you sure you want to delete these comments and all their children?'),
'admin/content/comment', t('This action cannot be undone.'),
t('Delete comments'), t('Cancel'));
}
}
/**
* Post deletion callback for multiple comment deletion.
* Perform the actual comment deletion.
*/
function comment_multiple_delete_confirm_post() {
function comment_multiple_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
foreach ($form_state['values']['comments'] as $cid => $value) {
$comment = _comment_load($cid);
_comment_delete_thread($comment);
_comment_update_node_statistics($comment->nid);
}
cache_clear_all();
drupal_set_message(t('The comments have been deleted.'));
}
drupal_goto('admin/content/comment');
}
/**

View File

@ -1729,67 +1729,29 @@ function theme_node_admin_nodes($form) {
function node_multiple_delete_confirm(&$form_state) {
$edit = $form_state['post'];
$form['nodes']['#tree'] = TRUE;
$form['prefix'] = array('#value' => '<ul>');
// array_filter() returns only elements with TRUE values.
$nids = array_filter($edit['nodes']);
$nodes = db_query('SELECT nid, title, type FROM {node} WHERE nid IN(%s)', implode(', ', $nids));
while ($node = db_fetch_object($nodes)) {
// This is a placeholder -- preserves proper ordering in the confirm form.
$form["node_$node->nid"] = array();
// Start a new package for each node.
drupal_delete_initiate('node', $node->nid);
// Add the confirm form piece for this node.
drupal_delete_add_form_elements(
array(
"node_$node->nid" => array(
'#value' => check_plain($node->title),
'#prefix' => '<li>',
'#suffix' => "</li>\n",
),
'nodes' => array(
"node_$node->nid" => array(
'#type' => 'hidden',
'#value' => $node->nid,
)
)
)
);
drupal_delete_add_callback(array('node_delete_post' => array($node->nid, $node->title, $node->type)));
node_delete($node->nid);
$form['nodes'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
// array_filter returns only elements with TRUE values
foreach (array_filter($edit['nodes']) as $nid => $value) {
$title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $nid));
$form['nodes'][$nid] = array('#type' => 'hidden', '#value' => $nid, '#prefix' => '<li>', '#suffix' => check_plain($title) ."</li>\n");
}
$form['suffix'] = array('#value' => '</ul>');
$form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
$form['operation'] = array(
'#type' => 'hidden',
'#value' => 'delete',
);
// New package for the main admin callback.
drupal_delete_initiate('node', 'admin');
// Add the main callback for the mass deletion last.
drupal_delete_add_callback(array('node_multiple_delete_confirm_post' => array()));
return drupal_delete_confirm(
array(
'form' => $form,
'question' => t('Are you sure you want to delete these items?'),
'path' => 'admin/content/node',
'yes' => t('Delete all'),
'destination' => 'admin/content/node',
)
);
return confirm_form($form,
t('Are you sure you want to delete these items?'),
'admin/content/node', t('This action cannot be undone.'),
t('Delete all'), t('Cancel'));
}
function node_multiple_delete_confirm_post() {
// Clear the cache so an anonymous poster can see the nodes being deleted.
cache_clear_all();
drupal_set_message(t('The items have been deleted.'));
function node_multiple_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
foreach ($form_state['values']['nodes'] as $nid => $value) {
node_delete($nid);
}
drupal_set_message(t('The items have been deleted.'));
}
$form_state['redirect'] = 'admin/content/node';
return;
}
/**
@ -1871,44 +1833,32 @@ function node_revision_revert($nid, $revision) {
* revision is deleted.
*/
function node_revision_delete($nid, $revision) {
$node = node_load($nid);
if (user_access('administer nodes')) {
$node = node_load($nid);
if (node_access('delete', $node)) {
// Don't delete the current revision
if ($revision != $node->vid) {
$node = node_load($nid, $revision);
if (user_access('administer nodes') && node_access('delete', $node)) {
db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $nid, $revision);
node_invoke_nodeapi($node, 'delete revision');
drupal_set_message(t('Deleted %title revision %revision.', array('%title' => $node->title, '%revision' => $revision)));
watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node->type, '%title' => $node->title, '%revision' => $revision));
}
// Don't delete the current revision
if ($revision != $node->vid) {
$node = node_load($nid, $revision);
drupal_delete_initiate('node_revision', $revision);
drupal_delete_add_callback(array('node_revision_delete_post' => array($node, $revision)));
drupal_delete_add_query('DELETE FROM {node_revisions} WHERE vid = %d', $revision);
node_invoke_nodeapi($node, 'delete revision');
// Back to revisions page if multiple revisions exist.
if (db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $node->nid)) > 2) {
$destination = "node/$node->nid/revisions";
else {
drupal_set_message(t('Deletion failed. You tried to delete the current revision.'));
}
if (db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $nid)) > 1) {
drupal_goto("node/$nid/revisions");
}
else {
$destination = "node/$node->nid";
drupal_goto("node/$nid");
}
drupal_delete_execute($destination);
}
else {
drupal_set_message(t('Deletion failed. You tried to delete the current revision.'));
}
}
else {
drupal_access_denied();
}
}
/**
* Post revision deletion operations.
*/
function node_revision_delete_post($node, $revision) {
drupal_set_message(t('Deleted %title revision %revision.', array('%title' => $node->title, '%revision' => $revision)));
watchdog('content', '@type: deleted %title revision %revision.', array('@type' => t($node->type), '%title' => $node->title, '%revision' => $revision));
drupal_access_denied();
}
/**