Index: database/database.mysql =================================================================== RCS file: /cvs/drupal/drupal/database/database.mysql,v retrieving revision 1.201 diff -u -F^function -r1.201 database.mysql --- database/database.mysql 18 Oct 2005 14:41:26 -0000 1.201 +++ database/database.mysql 27 Oct 2005 20:38:44 -0000 @@ -239,6 +239,20 @@ ) TYPE=MyISAM; -- +-- Table structure for table 'deleted' +-- + +CREATE TABLE deleted ( + tid int(10) NOT NULL default 0, + did int(10) NOT NULL default 0, + root_row varchar(255) NOT NULL default '', + data longtext NOT NULL, + preview longtext NOT NULL, + timestamp int(10) unsigned NOT NULL default 0, + PRIMARY KEY (tid) +) TYPE=MyISAM; + +-- -- Table structure for table 'files' -- Index: database/database.pgsql =================================================================== RCS file: /cvs/drupal/drupal/database/database.pgsql,v retrieving revision 1.140 diff -u -F^function -r1.140 database.pgsql --- database/database.pgsql 18 Oct 2005 14:41:26 -0000 1.140 +++ database/database.pgsql 27 Oct 2005 20:38:44 -0000 @@ -235,6 +235,20 @@ ); -- +-- Table structure for table 'deleted' +-- + +CREATE TABLE deleted ( + tid integer NOT NULL default '0', + did integer NOT NULL default '0', + root_row text NOT NULL default '', + data text NOT NULL default '', + preview text NOT NULL default '', + timestamp integer NOT NULL default '0', + PRIMARY KEY (tid) +); + +-- -- Table structure for table 'files' -- Index: database/updates.inc =================================================================== RCS file: /cvs/drupal/drupal/database/updates.inc,v retrieving revision 1.140 diff -u -F^function -r1.140 updates.inc --- database/updates.inc 22 Oct 2005 15:14:46 -0000 1.140 +++ database/updates.inc 27 Oct 2005 20:38:45 -0000 @@ -67,7 +67,8 @@ "2005-09-07" => "update_147", "2005-09-18" => "update_148", "2005-09-27" => "update_149", - "2005-10-15" => "update_150" + "2005-10-15" => "update_150", + "2005-10-27" => "update_151" ); function update_110() { @@ -919,6 +920,38 @@ function update_150() { return $ret; } +function update_151() { + $ret = array(); + + switch ($GLOBALS['db_type']) { + case 'mysqli': + case 'mysql': + $ret[] = update_sql("CREATE TABLE deleted ( + tid int(10) NOT NULL default 0, + did int(10) NOT NULL default 0, + root_row varchar(255) NOT NULL default '', + data longtext NOT NULL, + preview longtext NOT NULL, + timestamp int(10) unsigned NOT NULL default 0, + PRIMARY KEY (tid) + )"); + break; + case 'pgsql': + $ret[] = update_sql("CREATE TABLE deleted ( + tid integer NOT NULL default 0 PRIMARY KEY, + did integer NOT NULL default 0, + root_row text NOT NULL default '', + data text NOT NULL, + preview text NOT NULL, + timestamp integer NOT NULL default 0 + )"); + break; + default: + break; + } + return $ret; +} + function update_sql($sql) { $edit = $_POST["edit"]; $result = db_query($sql); Index: includes/locale.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/locale.inc,v retrieving revision 1.56 diff -u -F^function -r1.56 locale.inc --- includes/locale.inc 21 Oct 2005 11:14:28 -0000 1.56 +++ includes/locale.inc 27 Oct 2005 20:38:47 -0000 @@ -935,10 +935,14 @@ function _locale_export_remove_plural($e } function _locale_string_delete($lid) { - db_query('DELETE FROM {locales_source} WHERE lid = %d', $lid); - db_query('DELETE FROM {locales_target} WHERE lid = %d', $lid); + $did = db_next_id('{deleted}_did'); + $result = db_fetch_object(db_query('SELECT source, location FROM {locales_source} WHERE lid = %d', $lid)); + $preview = array('source' => $result->source, 'location' => $result->location); + system_trash($did, 'locale', $preview, 'DELETE FROM {locales_source} WHERE lid = %d', $lid); + system_trash($did, NULL, NULL, 'DELETE FROM {locales_target} WHERE lid = %d', $lid); locale_refresh_cache(); - drupal_set_message(t('The string has been removed.')); + drupal_set_message(t('The string has been moved to trash.')); + drupal_goto('admin/locale/string/search'); } /** Index: modules/block.module =================================================================== RCS file: /cvs/drupal/drupal/modules/block.module,v retrieving revision 1.184 diff -u -F^function -r1.184 block.module --- modules/block.module 22 Oct 2005 15:14:46 -0000 1.184 +++ modules/block.module 27 Oct 2005 20:38:48 -0000 @@ -408,10 +408,12 @@ function block_box_add() { */ function block_box_delete($bid = 0) { $box = block_box_get($bid); - $form['info'] = array('#type' => 'hidden', '#value' => $box['info'] ? $box['info'] : $box['title']); - $form['bid'] = array('#type' => 'hidden', '#value' => $bid); - - return confirm_form('block_box_delete_confirm', $form, t('Are you sure you want to delete the block %name?', array('%name' => theme('placeholder', $info))), 'admin/block', '', t('Delete'), t('Cancel')); + $did = db_next_id('{deleted}_did'); + $preview = array('title' => $box['title'], 'info' => $box['info'], 'body' => $box['body']); + system_trash($did, 'block', $preview, 'DELETE FROM {boxes} WHERE bid = %d', $bid); + drupal_set_message(t('The block %name has been moved to trash.', array('%name' => theme('placeholder', $box['info'])))); + cache_clear_all(); + drupal_goto('admin/block'); } /** @@ -419,10 +421,7 @@ function block_box_delete($bid = 0) { */ function block_box_delete_confirm_execute($form_id, $edit) { $form = $GLOBALS['form_values']; - db_query('DELETE FROM {boxes} WHERE bid = %d', $form['bid']); - drupal_set_message(t('The block %name has been removed.', array('%name' => theme('placeholder', $form['info'])))); - cache_clear_all(); - drupal_goto('admin/block'); + }; Index: modules/book.module =================================================================== RCS file: /cvs/drupal/drupal/modules/book.module,v retrieving revision 1.325 diff -u -F^function -r1.325 book.module --- modules/book.module 24 Oct 2005 19:03:09 -0000 1.325 +++ modules/book.module 27 Oct 2005 20:38:49 -0000 @@ -217,7 +217,7 @@ function book_update($node) { * Implementation of hook_delete(). */ function book_delete(&$node) { - db_query('DELETE FROM {book} WHERE nid = %d', $node->nid); + system_trash($node->did, NULL, NULL, 'DELETE FROM {book} WHERE nid = %d', $node->nid); } /** @@ -295,7 +295,9 @@ function book_outline() { break; case t('Remove from book outline'): - db_query('DELETE FROM {book} WHERE nid = %d', $node->nid); + $did = db_next_id('{deleted}_did'); + $preview = array('title' => $node-title, 'body' => $node->body); + system_trash($did, 'book', $preview, 'DELETE FROM {book} WHERE nid = %d', $node->nid); drupal_set_message(t('The post has been removed from the book.')); drupal_goto("node/$node->nid"); break; Index: modules/comment.module =================================================================== RCS file: /cvs/drupal/drupal/modules/comment.module,v retrieving revision 1.384 diff -u -F^function -r1.384 comment.module --- modules/comment.module 20 Oct 2005 09:27:36 -0000 1.384 +++ modules/comment.module 27 Oct 2005 20:38:51 -0000 @@ -232,8 +232,8 @@ function comment_nodeapi(&$node, $op, $a break; case 'delete': - db_query('DELETE FROM {comments} WHERE nid = %d', $node->nid); - db_query('DELETE FROM {node_comment_statistics} WHERE nid = %d', $node->nid); + system_trash($node->did, NULL, NULL, 'DELETE FROM {comments} WHERE nid = %d', $node->nid); + system_trash($node->did, NULL, NULL, 'DELETE FROM {node_comment_statistics} WHERE nid = %d', $node->nid); break; case 'update index': @@ -909,12 +909,10 @@ function comment_delete($cid) { $comment = db_fetch_object(db_query('SELECT c.*, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.cid = %d', $cid)); $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - $output = ''; - // We'll only delete if the user has confirmed the // deletion using the form in our else clause below. - if ($comment->cid && $_POST['edit']['confirm']) { - drupal_set_message(t('The comment and all its replies have been deleted.')); + if ($comment->cid) { + drupal_set_message(t('The comment and all its replies have been moved to trash.')); // Delete comment and its replies. _comment_delete_thread($comment); @@ -926,20 +924,10 @@ function comment_delete($cid) { drupal_goto("node/$comment->nid"); } - else if ($comment->cid) { - $output = confirm_form('comment_confirm_delete', - array(), - t('Are you sure you want to delete the comment %title?', array('%title' => theme('placeholder', $comment->subject))), - 'node/'. $comment->nid, - t('Any replies to this comment will be lost. This action cannot be undone.'), - t('Delete'), - t('Cancel')); - } else { drupal_set_message(t('The comment no longer exists.')); } - return $output; } /** @@ -1289,9 +1277,18 @@ function theme_comment_post_forbidden() } function _comment_delete_thread($comment) { + static $did; + if ($did) { + $root_row = NULL; + $preview = NULL; + } else { + $did = db_next_id('{deleted}_did'); + $root_row = 'comment'; + $preview = array('subject' => $comment->subject, 'comment' => $comment->comment); + } // Delete the comment: - db_query('DELETE FROM {comments} WHERE cid = %d', $comment->cid); - watchdog('content', t('Comment: deleted %subject.', array('%subject' => theme('placeholder', $comment->subject)))); + system_trash($did, $root_row, $preview, 'DELETE FROM {comments} WHERE cid = %d', $comment->cid); + watchdog('content', t('Comment: moved %subject to trash.', array('%subject' => theme('placeholder', $comment->subject)))); comment_invoke_comment($comment, 'delete'); Index: modules/contact.module =================================================================== RCS file: /cvs/drupal/drupal/modules/contact.module,v retrieving revision 1.26 diff -u -F^function -r1.26 contact.module --- modules/contact.module 11 Oct 2005 19:44:34 -0000 1.26 +++ modules/contact.module 27 Oct 2005 20:38:51 -0000 @@ -197,18 +197,11 @@ function contact_admin_edit($category = } function contact_admin_delete($category) { - if ($_POST['op'] != t('Delete')) { - return confirm_form('contact_admin_delete', array(), - t('Are you sure you want to delete %category?', array('%category' => theme('placeholder', $category))), - 'admin/contact', - t('This action cannot be undone.'), - t('Delete'), - t('Cancel')); - } - else { - db_query("DELETE FROM {contact} WHERE category = '%s'", $category); + $did = db_next_id('{deleted}_did'); + $preview = array('title' => $category); + system_trash($did, 'contact', $preview, "DELETE FROM {contact} WHERE category = '%s'", $category); + drupal_set_message(t('Contact category %category moved to trash', array('%category' => t($category)))); drupal_goto('admin/contact'); - } } Index: modules/filter.module =================================================================== RCS file: /cvs/drupal/drupal/modules/filter.module,v retrieving revision 1.77 diff -u -F^function -r1.77 filter.module --- modules/filter.module 22 Oct 2005 15:14:46 -0000 1.77 +++ modules/filter.module 27 Oct 2005 20:38:52 -0000 @@ -339,33 +339,24 @@ function filter_admin_add() { * Menu callback; confirm deletion of a format. */ function filter_admin_delete() { - $edit = $_POST['edit']; - if ($edit['confirm']) { - if ($edit['format'] != variable_get('filter_default_format', 1)) { - db_query("DELETE FROM {filter_formats} WHERE format = %d", $edit['format']); - db_query("DELETE FROM {filters} WHERE format = %d", $edit['format']); - - $default = variable_get('filter_default_format', 1); - db_query("UPDATE {node_revisions} SET format = %d WHERE format = %d", $default, $edit['format']); - db_query("UPDATE {comments} SET format = %d WHERE format = %d", $default, $edit['format']); - db_query("UPDATE {boxes} SET format = %d WHERE format = %d", $default, $edit['format']); - - cache_clear_all('filter:'. $edit['format'], true); - - drupal_set_message(t('Deleted input format %format.', array('%format' => theme('placeholder', $edit['name'])))); - } - drupal_goto('admin/filters'); - } - $format = arg(3); - $format = db_fetch_object(db_query('SELECT * FROM {filter_formats} WHERE format = %d', $format)); - - $form['format'] = array('#type' => 'hidden', '#value' => $format->format); - $form['name'] = array('#type' => 'hidden', '#value' => $format->name); - - return confirm_form('filter_admin_delete', $form, t('Are you sure you want to delete the input format %format?', array('%format' => theme('placeholder', $format->name))), 'admin/filters', t('If you have any content left in this input format, it will be switched to the default input format. This action cannot be undone.'), t('Delete'), t('Cancel')); + if ($format != variable_get('filter_default_format', 1)) { + $result = db_fetch_object(db_query('SELECT * FROM {filter_formats} WHERE format = %d', $format)); + $did = db_next_id('{deleted}_did'); + $preview = array('name' => $result->name); + system_trash($did, 'filter', $preview, "DELETE FROM {filters} WHERE format = %d", $format); + system_trash($did, NULL, NULL, "DELETE FROM {filter_formats} WHERE format = %d", $format); + + $default = variable_get('filter_default_format', 1); + db_query("UPDATE {node_revisions} SET format = %d WHERE format = %d", $default, $format); + db_query("UPDATE {comments} SET format = %d WHERE format = %d", $default, $format); + db_query("UPDATE {boxes} SET format = %d WHERE format = %d", $default, $format); + cache_clear_all('filter:'. $format, true); + drupal_set_message(t('Input format %format sent to trash.', array('%format' => theme('placeholder', $result->name)))); + } + drupal_goto('admin/filters'); } /** Index: modules/forum.module =================================================================== RCS file: /cvs/drupal/drupal/modules/forum.module,v retrieving revision 1.277 diff -u -F^function -r1.277 forum.module --- modules/forum.module 21 Oct 2005 11:12:46 -0000 1.277 +++ modules/forum.module 27 Oct 2005 20:38:53 -0000 @@ -86,14 +86,8 @@ function forum_admin() { } break; case t('Delete'): - if (!$edit['confirm']) { - $output = _forum_confirm_delete($edit['tid']); - break; - } - else { $name = $edit['name']; $edit['name'] = 0; - } case t('Submit'): $status = taxonomy_save_term($edit); if (arg(3) == 'container') { @@ -139,10 +133,10 @@ function forum_admin() { function forum_taxonomy($op, $type, $object = NULL) { if ($op == 'delete' && $type == 'term' && $object->vid == _forum_get_vid()) { $results = db_query('SELECT f.nid FROM {forum} f WHERE f.tid = %d', $object->tid); - while ($node = db_fetch_object($results)) { - $edit['nid'] = $node->nid; - $edit['confirm'] = TRUE; - node_delete($edit); + while ($nid = db_fetch_object($results)) { + $node = node_load($nid->nid); + $node->did = $object->did; + node_delete($node); } } elseif ($op == 'delete' && $type == 'vocabulary' && $object->vid == _forum_get_vid()) { @@ -151,20 +145,6 @@ function forum_taxonomy($op, $type, $obj } /** - * Returns a confirmation page for deleting a forum taxonomy term - * - * @param $tid ID of the term to be deleted - */ -function _forum_confirm_delete($tid) { - $term = taxonomy_get_term($tid); - - $form['tid'] = array('#type' => 'hidden', '#value' => $tid); - - return confirm_form('forum_confirm_delete', $form, t('Are you sure you want to delete the forum %name?', array('%name' => theme('placeholder', $term->name))), - 'admin/forums', t('Deleting a forum or container will delete all sub-forums as well. This action cannot be undone.'), t('Delete'), t('Cancel')); -} - -/** * Returns a form for adding a container to the forum vocabulary * * @param $edit Associative array containing a container term to be added or edited. @@ -593,7 +573,7 @@ function forum_insert($node) { * Implementation of hook_delete(). */ function forum_delete(&$node) { - db_query('DELETE FROM {forum} WHERE nid = %d', $node->nid); + system_trash($node->did, NULL, NULL, 'DELETE FROM {forum} WHERE nid = %d', $node->nid); } /** Index: modules/locale.module =================================================================== RCS file: /cvs/drupal/drupal/modules/locale.module,v retrieving revision 1.128 diff -u -F^function -r1.128 locale.module --- modules/locale.module 13 Oct 2005 10:02:31 -0000 1.128 +++ modules/locale.module 27 Oct 2005 20:38:54 -0000 @@ -294,39 +294,28 @@ function locale_admin_manage() { function locale_admin_manage_delete_screen() { include_once './includes/locale.inc'; $langcode = arg(4); - $edit = $_POST['edit']; - - // Check confirmation and if so, delete language - if ($edit['confirm']) { - $languages = locale_supported_languages(FALSE, TRUE); - if (isset($languages['name'][$edit['langcode']])) { - db_query("DELETE FROM {locales_meta} WHERE locale = '%s'", $edit['langcode']); - db_query("DELETE FROM {locales_target} WHERE locale = '%s'", $edit['langcode']); - $message = t('The language %locale has been removed.', array('%locale' => theme('placeholder', t($languages['name'][$edit['langcode']])))); - drupal_set_message($message); - watchdog('locale', $message); - } - - // Changing the locale settings impacts the interface: - cache_clear_all(); - drupal_goto('admin/locale/language/overview'); - } - + // Do not allow deletion of English locale if ($langcode == 'en') { drupal_goto('admin/locale/language/overview'); return; } - // For other locales, warn user that data loss is ahead + // Delete language $languages = locale_supported_languages(FALSE, TRUE); + if (isset($languages['name'][$langcode])) { + $did = db_next_id('{deleted}_did'); + $preview = array('language code' => $langcode, 'name' => $languages['name'][$langcode]); + system_trash($did, 'locale', $preview, "DELETE FROM {locales_meta} WHERE locale = '%s'", $langcode); + system_trash($did, NULL, NULL, "DELETE FROM {locales_target} WHERE locale = '%s'", $langcode); + $message = t('The language %locale has been sent to trash.', array('%locale' => theme('placeholder', t($languages['name'][$langcode])))); + drupal_set_message($message); + watchdog('locale', $message); + } - $form['langcode'] = array('#type' => 'hidden', '#value' => $langcode); - return confirm_form('locale_admin_manage_delete_screen', $form, - t('Are you sure you want to delete the language %name?', array('%name' => theme('placeholder', t($languages['name'][$langcode])))), - 'admin/locale/language/overview', - t('Deleting a language will remove all data associated with it. This action cannot be undone.'), - t('Delete'), t('Cancel')); + // Changing the locale settings impacts the interface: + cache_clear_all(); + drupal_goto('admin/locale/language/overview'); } /** Index: modules/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node.module,v retrieving revision 1.541 diff -u -F^function -r1.541 node.module --- modules/node.module 26 Oct 2005 14:49:59 -0000 1.541 +++ modules/node.module 27 Oct 2005 20:38:56 -0000 @@ -866,6 +866,9 @@ function node_menu($may_cache) { 'access' => user_access('administer nodes')); $items[] = array('path' => 'admin/node/action', 'title' => t('content'), 'type' => MENU_CALLBACK); + $items[] = array('path' => 'admin/node/batch_delete', 'title' => t('content'), + 'type' => MENU_CALLBACK, 'access' => user_access('administer nodes'), + 'callback' => 'node_multiple_delete_confirm'); $items[] = array('path' => 'admin/node/overview', 'title' => t('list'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10); $items[] = array('path' => 'admin/settings/node', 'title' => t('posts'), @@ -907,7 +910,7 @@ function node_menu($may_cache) { 'weight' => 1, 'type' => MENU_LOCAL_TASK); $items[] = array('path' => 'node/'. arg(1) .'/delete', 'title' => t('delete'), - 'callback' => 'node_delete_page', + 'callback' => 'node_delete_confirm', 'access' => node_access('delete', $node), 'weight' => 1, 'type' => MENU_CALLBACK); @@ -1100,18 +1103,20 @@ function node_filter_form_execute() { * Generate the content administration overview. */ function node_admin_nodes_execute($form_id, $edit) { - $operations = node_operations(); - if ($operations[$edit['operation']][1]) { - // Flag changes - $operation = $operations[$edit['operation']][1]; - foreach ($edit['nodes'] as $nid => $value) { - if ($value) { - db_query($operation, $nid); + if ($edit['operation'] != 'delete') { + $operations = node_operations(); + if ($operations[$edit['operation']][1]) { + // Flag changes + $operation = $operations[$edit['operation']][1]; + foreach ($edit['nodes'] as $nid => $value) { + if ($value) { + db_query($operation, $nid); + } } + drupal_set_message(t('The update has been performed.')); } - drupal_set_message(t('The update has been performed.')); + drupal_goto('admin/node'); } - drupal_goto('admin/node'); } function node_admin_nodes_validate($form_id, $edit) { @@ -1160,7 +1165,7 @@ function node_admin_nodes() { // If you are attempting to delete nodes, display the multiple deletion form. if ($form_values['operation'] == 'delete') { - $output = node_multiple_delete_form(); + $output = node_multiple_delete_confirm(); } return $output; @@ -1197,30 +1202,79 @@ function theme_node_admin_nodes($form) { return $output; } -function node_multiple_delete_form() { +function node_multiple_delete_confirm() { global $form_values; - $form['nodes'] = array('#prefix' => ''); - foreach ($form_values['nodes'] as $nid => $value) { - if ($value) { - $title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $nid)); - $form['nodes'][$nid] = array('#type' => 'hidden', '#value' => $nid, '#tree' => TRUE, '#prefix' => '
  • ', '#suffix' => check_plain($title) .'
  • '); + $edit = $_POST['edit']; + // Grab nids from url for execute + if ($edit['confirm']) { + $nids = array_keys($edit['checkboxes']); + } else { + // Keep only checked nodes' nids + $nids = array_keys(array_intersect($form_values['nodes'], array('1'))); + } + foreach ($nids as $nid) { + $node = node_load($nid); + $extras = node_invoke_nodeapi($node, 'delete pre'); + // No extras, just delete + if (!count($extras)) { + node_delete($node); + } else { + // Add node and extras to the list only if no module has cancelled deletion for this node. + if (!in_array(FALSE, $extras)) { + $form['nodes'][$node->nid] = array('#type' => 'value', '#value' => 1); + $form['title'][$node->nid] = array('#type' => 'markup', '#value' => check_plain($node->title)); + $form['extras'][$node->nid] = $extras; + $options[$node->nid] = ''; + } } } - $form['operation'] = array('#type' => 'hidden', '#value' => 'delete'); - - return confirm_form('node_multiple_delete_form', $form, - t('Are you sure you want to delete these items?'), - 'admin/node', t('This action cannot be undone.'), - t('Delete all'), t('Cancel')); + if ($edit['confirm']) { + confirm_form('node_multiple_delete_confirm', $form, + t('The following items need to be reviewed'), + 'admin/node', t('Selected items will be sent to trash.'), + t('Delete selected'), t('Cancel')); + } + // Back to the admin page if no nodes can be deleted. + if (!count($options)) { + drupal_goto('admin/node'); + } else { + $form['nodes']['#tree'] = TRUE; + $form['title']['#tree'] = TRUE; + $form['extras']['#tree'] = TRUE; + $form['checkboxes'] = array('#type' => 'checkboxes', '#options' => $options); + $form['confirm'] = array('#type' => 'value', '#value' => 1); + $form['operation'] = array('#type' => 'value', '#value' => 'delete'); + $form['#method'] = 'post'; + $form['#action'] = url('admin/node/batch_delete'); + return confirm_form('node_multiple_delete_confirm', $form, + t('The following items need to be reviewed'), + 'admin/node', t('Selected items will be sent to trash.'), + t('Delete selected'), t('Cancel')); + } } +function theme_node_multiple_delete_confirm($form) { + $rows = array(); + $header = array(''); + $output = ''; + foreach(element_children($form['nodes']) as $nid) { + $rows[] = array('
    '. ''. form_render($form['title'][$nid]) .''. form_render($form['checkboxes'][$nid]) .'
    '. form_render($form['extras'][$nid]) . form_render($form['nodes'][$nid])); + $rows[] = array(''); + } + $output .= theme('table', $header, $rows); + $output .= form_render($form); + return $output; +} -function node_multiple_delete_form_execute($form_id, $edit) { - if ($edit['confirm']) { - foreach ($edit['nodes'] as $nid => $value) { - node_delete(array('nid' => $nid, 'confirm' => 1)); +function node_multiple_delete_confirm_execute($form_id, $form_values) { + $edit = $_POST['edit']; + if ($form_values['confirm']) { + foreach ($edit['checkboxes'] as $nid => $value) { + // Merge extra confirm data with node + $node = object2array(node_load($nid)); + $node = array2object(array_merge($node, $edit['extras'][$nid])); + node_delete($node); } - drupal_set_message(t('The items have been deleted.')); } drupal_goto('admin/node'); } @@ -1334,8 +1388,11 @@ function node_revision_delete($nid, $rev $count_revisions = db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $nid)); // Don't delete the last revision of the node or the current revision if ($count_revisions > 1) { - db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $nid, $revision); - drupal_set_message(t('Deleted revision with the ID %revision.', array('%revision' => theme('placeholder', $revision)))); + $node = node_load($nid); + $did = db_next_id('{deleted}_did'); + $preview = array('title' => $node->title, 'body' => $node->body); + system_trash($did, 'node revision', $preview, "DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $nid, $revision); + drupal_set_message(t('Revision ID %revision moved to trash.', array('%revision' => theme('placeholder', $revision)))); } else { drupal_set_message(t('Deletion failed. You tried to delete the current revision.')); @@ -1847,29 +1904,72 @@ function node_form_execute($form_id, $ed /** * Ask for confirmation, and delete the node. */ -function node_delete($edit) { +function node_delete_confirm() { + $edit = $_POST['edit']; + $edit['nid'] = $edit['nid'] ? $edit['nid'] : arg(1); $node = node_load($edit['nid']); - if (node_access('delete', $node)) { - $form['nid'] = array('#type' => 'hidden', '#value' => $node->nid); - $output = confirm_form('node_delete_confirm', $form, - t('Are you sure you want to delete %title?', array('%title' => theme('placeholder', $node->title))), - $_GET['destination'] ? $_GET['destination'] : 'node/'. $node->nid, t('This action cannot be undone.'), - t('Delete'), t('Cancel') ); + $form['nid'] = array('#type' => 'value', '#value' => $node->nid); + $form['confirm'] = array('#type' => 'value', '#value' => 1); + // Check for extra info from modules + $extras = node_invoke_nodeapi($node, 'delete pre'); + $form['extras'] = $extras; + if ($edit['confirm']) { + confirm_form('node_delete_confirm', $form, + t('Are you sure you want to delete %title?', array('%title' => theme('placeholder', $node->title))), + $_GET['destination'] ? $_GET['destination'] : 'node/'. $node->nid, t('This action will send the + item to trash'), t('Delete'), t('Cancel')); + } + // No extras, just delete the node + if (!count($extras)) { + node_delete($node); + drupal_goto('node'); + } else { + // Cancel deletion if necessary, otherwise display confirm form + if (in_array(FALSE, $extras)) { + drupal_goto('node/'. $node->nid .'/edit'); + } else { + return confirm_form('node_delete_confirm', $form, + t('Are you sure you want to delete %title?', array('%title' => theme('placeholder', $node->title))), + $_GET['destination'] ? $_GET['destination'] : 'node/'. $node->nid, t('This action will send the + item to trash'), t('Delete'), t('Cancel')); + } + } } - - return $output; } -function node_delete_confirm_execute() { - global $form_values; - $node = node_load($form_values['nid']); - - if (node_access('delete', $node)) { +function node_delete_confirm_execute($form_id, $form_values) { + if ($form_values['confirm']) { + // Merge extra confirm data with node + $node = object2array(node_load($form_values['nid'])); + $node = array2object(array_merge($node, $form_values)); + node_delete($node); + drupal_goto('node'); + } +} - if ($form_values['confirm']) { - db_query('DELETE FROM {node} WHERE nid = %d', $node->nid); - db_query('DELETE FROM {node_revisions} WHERE nid = %d', $node->nid); +function node_delete($node) { + if (is_numeric($node)) { + $node = node_load($node); + } elseif (is_array($node)) { + $node = node_load($node['nid']); + } + if (!$node->did) { + $node->did = db_next_id('{deleted}_did'); + $root_row = 'node'; + } else { + $root_row = NULL; + } + $preview = array('title' => $node->title, 'body' => $node->body); + // Poll trash preview + if ($node->choice) { + foreach ($node->choice as $key => $array) { + $c++; + $preview["choice $c"] = $key['chtext']; + } + } + system_trash($node->did, $root_row, $preview, 'DELETE FROM {node} WHERE nid = %d', $node->nid); + system_trash($node->did, NULL, NULL, 'DELETE FROM {node_revisions} WHERE nid = %d', $node->nid); // Call the node-specific callback (if any): node_invoke($node, 'delete'); @@ -1882,11 +1982,8 @@ function node_delete_confirm_execute() { if (function_exists('search_wipe')) { search_wipe($node->nid, 'node'); } - + drupal_set_message(t('%title moved to trash.', array('%title' => theme('placeholder', $node->title)))); watchdog('content', t('%type: deleted %title.', array('%type' => theme('placeholder', t($node->type)), '%title' => theme('placeholder', $node->title)))); - } - } - drupal_goto('node'); } /** @@ -2008,20 +2105,6 @@ function node_page() { } /** - * Menu callback; the page for deleting a single node. - */ -function node_delete_page() { - $edit = $_POST['edit']; - $edit['nid'] = $edit['nid'] ? $edit['nid'] : arg(1); - $node = node_load($edit['nid']); - if (!($output = node_delete($edit))) { - drupal_set_message(t('%title has been deleted.', array('%title' => theme('placeholder', $node->title)))); - drupal_goto(''); - } - return $output; -} - -/** * Implementation of hook_update_index(). */ function node_update_index() { Index: modules/path.module =================================================================== RCS file: /cvs/drupal/drupal/modules/path.module,v retrieving revision 1.67 diff -u -F^function -r1.67 path.module --- modules/path.module 11 Oct 2005 19:44:35 -0000 1.67 +++ modules/path.module 27 Oct 2005 20:38:57 -0000 @@ -105,17 +105,24 @@ function path_admin_edit($pid = 0) { * Menu callback; handles deletion of an URL alias. */ function path_admin_delete($pid = 0) { - db_query('DELETE FROM {url_alias} WHERE pid = %d', $pid); - drupal_set_message(t('The alias has been deleted.')); + $did = db_next_id('{deleted}_did'); + $result = db_fetch_object(db_query('SELECT src, dst FROM {url_alias} WHERE pid = %d', $pid)); + $preview = array('source' => $result->src, 'destination' => $result->dst); + system_trash($did, 'url alias', $preview, 'DELETE FROM {url_alias} WHERE pid = %d', $pid); + drupal_set_message(t('The alias has been moved to trash.')); drupal_goto('admin/path'); } /** * Set an aliased path for a given Drupal path, preventing duplicates. */ -function path_set_alias($path = NULL, $alias = NULL, $pid = NULL) { +function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $node = NULL) { if ($path && !$alias) { - db_query("DELETE FROM {url_alias} WHERE src = '%s'", $path); + if ($node->did) { + system_trash($node->did, NULL, NULL, "DELETE FROM {url_alias} WHERE src = '%s'", $path); + } else { + db_query("DELETE FROM {url_alias} WHERE src = '%s'", $path); + } drupal_clear_path_cache(); } else if (!$path && $alias) { @@ -221,7 +228,7 @@ function path_nodeapi(&$node, $op, $arg) case 'delete': $path = "node/$node->nid"; if (drupal_get_path_alias($path) != $path) { - path_set_alias($path); + path_set_alias($path, NULL, NULL, $node); } break; } Index: modules/poll.module =================================================================== RCS file: /cvs/drupal/drupal/modules/poll.module,v retrieving revision 1.173 diff -u -F^function -r1.173 poll.module --- modules/poll.module 11 Oct 2005 19:44:35 -0000 1.173 +++ modules/poll.module 27 Oct 2005 20:38:57 -0000 @@ -83,9 +83,9 @@ function poll_cron() { /** * Implementation of hook_delete(). */ -function poll_delete($node) { - db_query("DELETE FROM {poll} WHERE nid = %d", $node->nid); - db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid); +function poll_delete(&$node) { + system_trash($node->did, NULL, NULL, "DELETE FROM {poll} WHERE nid = %d", $node->nid); + system_trash($node->did, NULL, NULL, "DELETE FROM {poll_choices} WHERE nid = %d", $node->nid); } /** Index: modules/profile.module =================================================================== RCS file: /cvs/drupal/drupal/modules/profile.module,v retrieving revision 1.115 diff -u -F^function -r1.115 profile.module --- modules/profile.module 21 Oct 2005 11:14:55 -0000 1.115 +++ modules/profile.module 27 Oct 2005 20:38:58 -0000 @@ -533,18 +533,13 @@ function profile_admin_edit($fid) { * Menu callback; deletes a field from all user profiles. */ function profile_admin_delete($fid) { - $field = db_fetch_object(db_query("SELECT title FROM {profile_fields} WHERE fid = %d", $fid)); - if ($_POST['edit']['confirm']) { - db_query('DELETE FROM {profile_fields} WHERE fid = %d', $fid); - cache_clear_all(); - drupal_set_message(t('The field %field has been deleted.', array('%field' => theme('placeholder', $field->title)))); - drupal_goto('admin/settings/profile'); - } - else { - return confirm_form('profile_confirm_delete', $form, t('Do you want to remove the field %field?', - array('%field' => $field->title)), - 'admin/settings/profile', '', t('Delete'), t('Cancel')); - } + $did = db_next_id('{deleted}_did'); + $result = db_fetch_object(db_query("SELECT title, explanation, category FROM {profile_fields} WHERE fid = %d", $fid)); + $preview = array('title' => $result->title, 'explanation' => $result->explanation, 'category' => $result->category); + system_trash($did, 'profile', $preview, 'DELETE FROM {profile_fields} WHERE fid = %d', $fid); + cache_clear_all(); + drupal_set_message(t('The field %field has been moved to trash.', array('%field' => theme('placeholder', $result->title)))); + drupal_goto('admin/settings/profile'); } function _profile_field_form($type, $edit = array()) { Index: modules/statistics.module =================================================================== RCS file: /cvs/drupal/drupal/modules/statistics.module,v retrieving revision 1.210 diff -u -F^function -r1.210 statistics.module --- modules/statistics.module 12 Oct 2005 01:00:24 -0000 1.210 +++ modules/statistics.module 27 Oct 2005 20:38:58 -0000 @@ -474,7 +474,7 @@ function statistics_nodeapi(&$node, $op, switch ($op) { case 'delete': // clean up statistics table when node is deleted - db_query('DELETE FROM {node_counter} WHERE nid = %d', $node->nid); + system_trash($node->did, NULL, NULL, 'DELETE FROM {node_counter} WHERE nid = %d', $node->nid); } } Index: modules/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system.module,v retrieving revision 1.247 diff -u -F^function -r1.247 system.module --- modules/system.module 26 Oct 2005 01:24:09 -0000 1.247 +++ modules/system.module 27 Oct 2005 20:39:00 -0000 @@ -138,6 +138,16 @@ function system_menu($may_cache) { } $items[] = array('path' => 'admin/modules', 'title' => t('modules'), 'callback' => 'system_modules', 'access' => $access); + + // Trash + $items[] = array('path' => 'admin/trash', 'title' => t('trash'), + 'callback' => 'system_admin_trash', 'access' => user_access('administer nodes')); + $items[] = array('path' => 'trash/preview', 'title' => t('preview'), + 'callback' => 'system_trash_preview', 'access' => TRUE, 'type' => MENU_CALLBACK); + $items[] = array('path' => 'trash/recover', 'title' => t('recover'), + 'callback' => 'system_trash_recover', 'access' => TRUE, 'type' => MENU_CALLBACK); + $items[] = array('path' => 'trash/delete', 'title' => t('delete'), + 'callback' => 'system_trash_delete', 'access' => TRUE, 'type' => MENU_CALLBACK); } return $items; @@ -1231,3 +1241,150 @@ function confirm_form($form_id, $form, $ $form['actions']['cancel'] = array('#value' => l($no ? $no : t('Cancel'), $path)); return drupal_get_form($form_id, $form, 'confirm_form'); } + +function system_admin_trash() { + $result = pager_query("SELECT * FROM deleted WHERE root_row != '' ORDER BY timestamp DESC", 25 , 0); + if (db_num_rows($result) == 0) { + $output = t('There are no items in your trash'); + } else { + $header = array(t('Deleted'), t('Type'), t('Title'), t('Operations')); + $rows = array(); + while ($recover = db_fetch_object($result)) { + $preview = unserialize($recover->preview); + $title = is_array($preview) ? array_shift($preview) : '[none]'; + $rows[] = array(format_date($recover->timestamp, 'small'), t($recover->root_row), t($title), l(t('Preview'), "trash/preview/$recover->tid") .' '. l(t('Recover'), "trash/recover/$recover->did/admin") .' '. l(t('Delete'), "trash/delete/$recover->did")); + } + $output = '

    '. l(t('Delete all trash'), 'trash/delete/all') .'

    '; + $output .= theme('table', $header, $rows) . theme('pager', NULL, 25, 0); + } + return $output; +} + +function system_trash($did, $root_row, $preview, $query) { + static $same_did; + // Grab the args for the query + $all_args = func_get_args(); + if (count($all_args) > 4) { + $args = array_slice($all_args, 4); + } else { + $args = array(); + } + // Turn delete into select and get result + $delete = preg_replace('/DELETE.*?FROM/i', 'SELECT * FROM', $query); + $result = db_query($delete, $args); + // Grab table name and store + $table = preg_match('/^DELETE FROM \{([^}]+)/', $query, $m); + $recover['table'] = $m[1]; + $root_row = $root_row ? $root_row : ''; + $preview = is_array($preview) ? serialize($preview) : ''; + // Store file info in case of later permanent deletion + if (module_exist('upload') && $root_row == 'node') { + $node = node_load($args[0]); + $file_info = upload_load($node); + $files = array(); + foreach ($file_info as $file) { + $filepaths[] = $file->filepath; + } + $recover['files'] = $filepaths; + } + // Loop through result inserting rows into deleted table + while ($recover['data'] = db_fetch_array($result)) { + $data = serialize($recover); + $tid = db_next_id('{deleted}_tid'); + db_query("INSERT INTO {deleted} SET tid = %d, did = %d, root_row = '%s', data = '%s', preview = '%s', timestamp = %d", $tid, $did, $root_row, $data, $preview, time()); + $root_row = ''; + $preview = ''; + } + // Delete from original table + db_query($query, $args); + // Only one message for each did + if ($same_did != $did) { + // Test if user can be directed to trash + if (user_access('administer nodes')) { + drupal_set_message(t('Click %here to recover from %trash.', array('%here' => l(t('here'), "trash/recover/$did/admin"), '%trash' => l(t('trash'), "admin/trash")))); + } else { + drupal_set_message(t('Click %here to recover.', array('%here' => l(t('here'), "trash/recover/$did")))); + } + $same_did = $did; + } +} + +function system_trash_preview($tid) { + if (user_access('administer nodes')) { + $did = db_result(db_query('SELECT did FROM {deleted} WHERE tid = %d', $tid)); + $output = ''; + $output .= '

    '. l(t('Recover'), "trash/recover/$did/admin") .' '. l(t('Delete'), "trash/delete/$did") .' '. l(t('Cancel'), "admin/trash") .'

    '; + $result = db_query("SELECT root_row, preview, timestamp FROM {deleted} WHERE tid = %d", $tid); + // Loop through grabbing preview data for all rows + while ($insert = db_fetch_object($result)) { + $values = array(); + $data = unserialize($insert->preview); + if ($data) { + foreach ($data as $key => $value) { + $values[] = ''. t($key) . ': '. t($value); + } + } + $output .= ''. t('Trashed') .': '. format_date($insert->timestamp, 'small') .'
    '; + $output .= ''. t('Type') .': '. t($insert->root_row) .'
    '; + $output .= '

    '. t('Data') .':

    '; + $output .= implode('
    ', $values); + } + return $output; + } else { + drupal_access_denied(); + } +} + +function system_trash_recover($did, $is_admin = FALSE) { + $result = db_query('SELECT * FROM deleted WHERE did = %d', $did); + // Loop through reinserting all rows + while ($insert = db_fetch_object($result)) { + $values = array(); + $recover = unserialize($insert->data); + foreach ($recover['data'] as $key => $value) { + $values[] = is_numeric($value) ? '%d' : '\'%s\''; + // Best guess at recovered node if present + if ($key == 'nid') { + $nid = $value; + } + } + db_query("INSERT INTO {$recover['table']} VALUES(". implode(', ', $values). ')', $recover['data']); + } + db_query('DELETE FROM {deleted} WHERE did = %d', $did); + $link = $nid ? t('The %item has been recovered', array('%item' => l(t('item'), "node/$nid"))) : t('The item has been recovered'); + drupal_set_message($link); + if ($is_admin == 'admin') { + drupal_goto('admin/trash'); + } else { + drupal_goto('node'); + } +} + +function system_trash_delete($did) { + if (user_access('administer nodes')) { + // Grab all node deletions and delete asscociated files + if (module_exist('upload')) { + if ($did == 'all') { + $result = db_query("SELECT * FROM {deleted} WHERE root_row = 'node'"); + } else { + $result = db_query("SELECT * FROM {deleted} WHERE did = %d AND root_row = 'node'", $did); + } + while ($node = db_fetch_object($result)) { + $data = unserialize($node->data); + foreach ($data['files'] as $filepath) { + file_delete($filepath); + } + } + } + // Permanently delete + if ($did == 'all') { + $result = db_query('DELETE FROM {deleted}'); + } else { + $result = db_query('DELETE FROM {deleted} WHERE did = %d', $did); + } + drupal_set_message(t('Permanent delete successful')); + drupal_goto("admin/trash"); + } else { + drupal_access_denied(); + } +} Index: modules/taxonomy.module =================================================================== RCS file: /cvs/drupal/drupal/modules/taxonomy.module,v retrieving revision 1.232 diff -u -F^function -r1.232 taxonomy.module --- modules/taxonomy.module 21 Oct 2005 11:12:46 -0000 1.232 +++ modules/taxonomy.module 27 Oct 2005 20:39:02 -0000 @@ -179,14 +179,19 @@ function taxonomy_save_vocabulary(&$edit function taxonomy_del_vocabulary($vid) { $vocabulary = taxonomy_get_vocabulary($vid); - - db_query('DELETE FROM {vocabulary} WHERE vid = %d', $vid); - db_query('DELETE FROM {vocabulary_node_types} WHERE vid = %d', $vid); + $did = db_next_id('{deleted}_did'); + $preview = array('name' => $vocabulary->name, 'description' => $vocabulary->description, 'children' => ''); + system_trash($did, 'vocabulary', $preview, 'DELETE FROM {vocabulary} WHERE vid = %d', $vid); + system_trash($did, NULL, NULL, 'DELETE FROM {vocabulary_node_types} WHERE vid = %d', $vid); $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid); while ($term = db_fetch_object($result)) { - taxonomy_del_term($term->tid); - } - + // Build terms preview as well + $previews = taxonomy_del_term($term->tid, $did); + $preview = array_merge($preview, $previews); + } + $preview = serialize($preview); + db_query("UPDATE {deleted} SET preview = '%s' WHERE did = %d AND root_row != ''", $preview, $did); + $vocabulary->did = $did; module_invoke_all('taxonomy', 'delete', 'vocabulary', $vocabulary); cache_clear_all(); @@ -194,20 +199,6 @@ function taxonomy_del_vocabulary($vid) { return SAVED_DELETED; } -function _taxonomy_confirm_del_vocabulary($vid) { - $vocabulary = taxonomy_get_vocabulary($vid); - - $form['type'] = array('#type' => 'hidden', '#value' => 'vocabulary'); - $form['vid'] = array('#type' => 'hidden', '#value' => $vid); - $form['name'] = array('#type' => 'hidden', '#value' => $vocabulary->name); - return confirm_form('vocabulary_confirm_delete', $form, - t('Are you sure you want to delete the vocabulary %title?', - array('%title' => theme('placeholder', $vocabulary->name))), - 'admin/taxonomy', t('Deleting a vocabulary will delete all the terms in it. This action cannot be undone.'), - t('Delete'), - t('Cancel')); -} - function taxonomy_form_term($edit = array()) { $vocabulary_id = isset($edit['vid']) ? $edit['vid'] : arg(4); $vocabulary = taxonomy_get_vocabulary($vocabulary_id); @@ -324,7 +315,12 @@ function taxonomy_save_term(&$edit) { return $status; } -function taxonomy_del_term($tid) { +function taxonomy_del_term($tid, $vocab_did = NULL) { + if ($vocab_did) { + $did = $vocab_did; + } else { + $did = db_next_id('{deleted}_did'); + } $tids = array($tid); while ($tids) { $children_tids = $orphans = array(); @@ -341,35 +337,33 @@ function taxonomy_del_term($tid) { } $term = taxonomy_get_term($tid); - - db_query('DELETE FROM {term_data} WHERE tid = %d', $tid); - db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $tid); - db_query('DELETE FROM {term_relation} WHERE tid1 = %d OR tid2 = %d', $tid, $tid); - db_query('DELETE FROM {term_synonym} WHERE tid = %d', $tid); - db_query('DELETE FROM {term_node} WHERE tid = %d', $tid); - + if (!$recurse && !$vocab_did) { + $root_row = 'taxonomy term'; + $preview = array('root term' => $term->name, 'description' => $term->description, 'children' => ''); + $recurse = 1; + } else { + $root_row = NULL; + $preview[] = $term->name; + } + system_trash($did, $root_row, NULL, 'DELETE FROM {term_data} WHERE tid = %d', $tid); + system_trash($did, NULL, NULL, 'DELETE FROM {term_hierarchy} WHERE tid = %d', $tid); + system_trash($did, NULL, NULL, 'DELETE FROM {term_relation} WHERE tid1 = %d OR tid2 = %d', $tid, $tid); + system_trash($did, NULL, NULL, 'DELETE FROM {term_synonym} WHERE tid = %d', $tid); + system_trash($did, NULL, NULL, 'DELETE FROM {term_node} WHERE tid = %d', $tid); + $term->did = $did; module_invoke_all('taxonomy', 'delete', 'term', $term); - drupal_set_message(t('Deleted term %name.', array('%name' => theme('placeholder', $term->name)))); + drupal_set_message(t('Moved term %name to trash.', array('%name' => theme('placeholder', $term->name)))); } $tids = $orphans; } - cache_clear_all(); -} - -function _taxonomy_confirm_del_term($tid) { - $term = taxonomy_get_term($tid); - - $form['type'] = array('#type' => 'hidden', '#value' => 'term'); - $form['tid'] = array('#type' => 'hidden', '#value' => $tid); - return confirm_form('term_confirm_delete', $form, - t('Are you sure you want to delete the term %title?', - array('%title' => theme('placeholder', $term->name))), - 'admin/taxonomy', - t('Deleting a term will delete all its children if there are any. This action cannot be undone.'), - t('Delete'), - t('Cancel')); + if (!$vocab_did) { + $preview = serialize($preview); + db_query("UPDATE {deleted} SET preview = '%s' WHERE did = %d AND root_row != ''", $preview, $did); + } else { + return $preview; + } } /** @@ -593,7 +587,7 @@ function taxonomy_node_validate(&$node) * Save term associations for a given node. */ function taxonomy_node_save($nid, $terms) { - taxonomy_node_delete($nid); + db_query('DELETE FROM {term_node} WHERE nid = %d', $nid); // Free tagging vocabularies do not send their tids in the form, // so we'll detect them here and process them independently. @@ -654,13 +648,6 @@ function taxonomy_node_save($nid, $terms } /** - * Remove associations of a node to its terms. - */ -function taxonomy_node_delete($nid) { - db_query('DELETE FROM {term_node} WHERE nid = %d', $nid); -} - -/** * Find all term objects related to a given term ID. */ function taxonomy_get_related($tid, $key = 'tid') { @@ -1041,7 +1028,7 @@ function taxonomy_nodeapi($node, $op, $a taxonomy_node_save($node->nid, $node->taxonomy); break; case 'delete': - taxonomy_node_delete($node->nid); + system_trash($node->did, NULL, NULL, 'DELETE FROM {term_node} WHERE nid = %d', $node->nid); break; case 'validate': taxonomy_node_validate($node); @@ -1170,20 +1157,9 @@ function taxonomy_admin() { } break; case t('Delete'): - if (!$edit['confirm']) { - if (arg(3) == 'vocabulary') { - $output = _taxonomy_confirm_del_vocabulary($edit['vid']); - } - else { - $output = _taxonomy_confirm_del_term($edit['tid']); - } - break; - } - else { - $deleted_name = $edit['name']; - $edit['name'] = 0; - // fall through: - } + $deleted_name = $edit['name']; + $edit['name'] = 0; + // fall through: case t('Submit'): if (arg(3) == 'vocabulary') { switch (taxonomy_save_vocabulary($edit)) { @@ -1194,7 +1170,7 @@ function taxonomy_admin() { drupal_set_message(t('Updated vocabulary %name.', array('%name' => theme('placeholder', $edit['name'])))); break; case SAVED_DELETED: - drupal_set_message(t('Deleted vocabulary %name.', array('%name' => theme('placeholder', $deleted_name)))); + drupal_set_message(t('Moved vocabulary %name to trash.', array('%name' => theme('placeholder', $deleted_name)))); break; } } Index: modules/upload.module =================================================================== RCS file: /cvs/drupal/drupal/modules/upload.module,v retrieving revision 1.55 diff -u -F^function -r1.55 upload.module --- modules/upload.module 11 Oct 2005 19:44:35 -0000 1.55 +++ modules/upload.module 27 Oct 2005 20:39:02 -0000 @@ -289,7 +289,7 @@ function upload_nodeapi(&$node, $op, $ar break; case 'delete': - upload_delete($node); + system_trash($node->did, NULL, NULL, "DELETE FROM {files} WHERE nid = %d", $node->nid); break; case 'search result': return $node->files ? format_plural(count($node->files), '1 attachment', '%count attachments') : null; @@ -380,14 +380,6 @@ function upload_save($node) { return; } -function upload_delete($node) { - $node->files = upload_load($node); - foreach ($node->files as $file) { - file_delete($file->filepath); - } - db_query("DELETE FROM {files} WHERE nid = %d", $node->nid); -} - function upload_form($node) { drupal_add_js('misc/progress.js'); drupal_add_js('misc/upload.js'); Index: modules/user.module =================================================================== RCS file: /cvs/drupal/drupal/modules/user.module,v retrieving revision 1.523 diff -u -F^function -r1.523 user.module --- modules/user.module 22 Oct 2005 15:14:46 -0000 1.523 +++ modules/user.module 27 Oct 2005 20:39:05 -0000 @@ -1257,18 +1257,16 @@ function user_edit($category = 'account' } } else if (arg(2) == 'delete') { - if ($edit['confirm']) { - db_query('DELETE FROM {users} WHERE uid = %d', $account->uid); - db_query('DELETE FROM {sessions} WHERE uid = %d', $account->uid); - db_query('DELETE FROM {users_roles} WHERE uid = %d', $account->uid); - db_query('DELETE FROM {authmap} WHERE uid = %d', $account->uid); - drupal_set_message(t('The account has been deleted.')); - module_invoke_all('user', 'delete', $edit, $account); - drupal_goto('admin/user'); - } - else { - return confirm_form('user_confirm_delete', $form, t('Are you sure you want to delete the account %name?', array('%name' => theme('placeholder', $account->name))), 'user/'. $account->uid, t('Deleting a user will remove all their submissions as well. This action cannot be undone.'), t('Delete')); - } + $did = db_next_id('{deleted}_did'); + $preview = array('name' => $account->name, 'email' => $account->mail); + system_trash($did, 'user', $preview, 'DELETE FROM {users} WHERE uid = %d', $account->uid); + db_query('DELETE FROM {sessions} WHERE uid = %d', $account->uid); + system_trash($did, NULL, NULL, 'DELETE FROM {users_roles} WHERE uid = %d', $account->uid); + system_trash($did, NULL, NULL, 'DELETE FROM {authmap} WHERE uid = %d', $account->uid); + drupal_set_message(t('The account has been moved to trash.')); + $account->did = $did; + module_invoke_all('user', 'delete', $edit, $account); + drupal_goto('admin/user'); } else if ($_POST['op'] == t('Delete')) { // Note: we redirect from user/uid/edit to user/uid/delete to make the tabs disappear. @@ -1458,20 +1456,9 @@ function user_admin_access_add($mask = N function user_admin_access_delete($aid = 0) { $access_types = array('user' => t('username'), 'mail' => t('e-mail')); $edit = db_fetch_object(db_query('SELECT aid, type, status, mask FROM {access} WHERE aid = %d', $aid)); - - $form = array(); - $form['aid'] = array('#type' => 'hidden', '#value' => $aid); - $output = confirm_form('user_admin_access_delete_confirm', $form, - t('Are you sure you want to delete the %type rule for %rule?', array('%type' => $access_types[$edit->type], '%rule' => theme('placeholder', $edit->mask))), - 'admin/access/rules', - t('This action cannot be undone.'), - t('Delete'), - t('Cancel')); - return $output; -} - -function user_admin_access_delete_confirm_execute($form_id, $edit) { - db_query('DELETE FROM {access} WHERE aid = %d', $edit['aid']); + $did = db_next_id('{deleted}_did'); + $preview = array('type' => $access_types[$edit->type], 'rule' => $edit->mask); + system_trash($did, 'access rule', $preview, 'DELETE FROM {access} WHERE aid = %d', $aid); drupal_set_message(t('The access rule has been deleted.')); drupal_goto('admin/access/rules'); } @@ -1665,8 +1652,10 @@ function user_admin_role() { } } else if ($op == t('Delete role')) { - db_query('DELETE FROM {role} WHERE rid = %d', $id); - db_query('DELETE FROM {permission} WHERE rid = %d', $id); + $did = db_next_id('{deleted}_did'); + $preview = db_fetch_array(db_query('SELECT name FROM {role} WHERE rid = %d', $id)); + system_trash($did, 'role', $preview, 'DELETE FROM {role} WHERE rid = %d', $id); + system_trash($did, NULL, NULL, 'DELETE FROM {permission} WHERE rid = %d', $id); // Update the users who have this role set: $result = db_query('SELECT DISTINCT(ur1.uid) FROM {users_roles} ur1 LEFT JOIN {users_roles} ur2 ON ur2.uid = ur1.uid WHERE ur1.rid = %d AND ur2.rid != ur1.rid', $id); @@ -1677,13 +1666,13 @@ function user_admin_role() { } if ($uid) { - db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid)); + system_trash($did, NULL, NULL, 'DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid)); } // Users with only the deleted role are put back in the authenticated users pool. db_query('UPDATE {users_roles} SET rid = %d WHERE rid = %d', _user_authenticated_id(), $id); - drupal_set_message(t('The role has been deleted.')); + drupal_set_message(t('The role has been moved to trash. All users with only this role have been moved to the authenticated users pool.')); drupal_goto('admin/access/roles'); } else if ($op == t('Add role')) {