=== modified file 'database/database.mysql'
--- database/database.mysql
+++ database/database.mysql
@@ -272,6 +272,44 @@ CREATE TABLE client_system (
/*!40100 DEFAULT CHARACTER SET utf8 */ ;
--
+-- Table structure for table `deleted`
+--
+
+CREATE TABLE deleted (
+ did int(10) unsigned NOT NULL default '0',
+ uid int(10) unsigned NOT NULL default '0',
+ rid varchar(255) NOT NULL default '',
+ name varchar(255) NOT NULL default '',
+ preview longtext NOT NULL,
+ extra longtext NOT NULL,
+ timestamp int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (did),
+ KEY uid (uid)
+) TYPE=MyISAM
+/*!40100 DEFAULT CHARACTER SET utf8 */ ;
+
+--
+-- Table structure for table `deleted_data`
+--
+
+CREATE TABLE deleted_data (
+ tid int(10) unsigned NOT NULL default '0',
+ did int(10) unsigned NOT NULL default '0',
+ dtable varchar(255) NOT NULL default '',
+ row_id int(10) unsigned NOT NULL default '0',
+ dcolumn varchar(255) NOT NULL default '',
+ data longtext NOT NULL,
+ PRIMARY KEY (tid),
+ KEY did (did),
+ KEY dtable (dtable),
+ KEY row_id (row_id),
+ KEY dcolumn (dcolumn)
+) TYPE=MyISAM
+/*!40100 DEFAULT CHARACTER SET utf8 */ ;
+
+--
-- Table structure for table 'files'
--
=== modified file 'database/database.pgsql'
--- database/database.pgsql
+++ database/database.pgsql
@@ -259,6 +259,42 @@ CREATE TABLE client_system (
);
--
+-- Table structure for table `deleted`
+--
+
+CREATE TABLE deleted (
+ did SERIAL,
+ uid integer NOT NULL default '0',
+ rid text NOT NULL default '',
+ name text NOT NULL default '',
+ preview text NOT NULL default '',
+ extra text NOT NULL default '',
+ timestamp integer NOT NULL default '0',
+ PRIMARY KEY (did)
+);
+CREATE INDEX deleted_uid_idx ON deleted(uid);
+
+--
+-- Table structure for table `deleted_data`
+--
+
+CREATE TABLE deleted_data (
+ tid SERIAL,
+ did integer NOT NULL default '0',
+ dtable text NOT NULL default '',
+ row_id integer NOT NULL default '0',
+ dcolumn text NOT NULL default '',
+ data text NOT NULL default '',
+ PRIMARY KEY (tid)
+);
+CREATE INDEX deleted_data_did_idx ON deleted_data(did);
+CREATE INDEX deleted_data_dtable_idx ON deleted_data(dtable);
+CREATE INDEX deleted_data_row_id_idx ON deleted_data(row_id);
+CREATE INDEX deleted_data_dcolumn_idx ON deleted_data(dcolumn);
+
+--
-- Table structure for table 'files'
--
=== modified file 'database/updates.inc'
--- database/updates.inc
+++ database/updates.inc
@@ -1344,7 +1344,6 @@ function system_update_164() {
}
}
}
-
$ret[] = update_sql('ALTER TABLE {poll} DROP polled');
return $ret;
@@ -1585,3 +1584,73 @@ function system_update_171() {
$ret[] = update_sql('DELETE FROM {users_roles} WHERE rid IN ('. DRUPAL_ANONYMOUS_RID. ', '. DRUPAL_AUTHENTICATED_RID. ')');
return $ret;
}
+
+/**
+ * Creates tables for the undo / trash can function.
+ */
+function system_update_172() {
+ $ret = array();
+
+ switch ($GLOBALS['db_type']) {
+ case 'mysqli':
+ case 'mysql':
+ $ret[] = update_sql("CREATE TABLE deleted (
+ did int(10) unsigned NOT NULL default '0',
+ uid int(10) unsigned NOT NULL default '0',
+ rid varchar(255) NOT NULL default '',
+ name varchar(255) NOT NULL default '',
+ preview longtext NOT NULL,
+ extra longtext NOT NULL,
+ timestamp int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (did),
+ KEY uid (uid)
+ ) TYPE=MyISAM;");
+ $ret[] = update_sql("CREATE TABLE deleted_data (
+ tid int(10) unsigned NOT NULL default '0',
+ did int(10) unsigned NOT NULL default '0',
+ dtable varchar(255) NOT NULL default '',
+ row_id int(10) unsigned NOT NULL default '0',
+ dcolumn varchar(255) NOT NULL default '',
+ data longtext NOT NULL,
+ PRIMARY KEY (tid),
+ KEY did (did),
+ KEY dtable (dtable),
+ KEY row_id (row_id),
+ KEY dcolumn (dcolumn)
+ ) TYPE=MyISAM");
+ break;
+ case 'pgsql':
+ $ret[] = update_sql("CREATE TABLE deleted (
+ did SERIAL,
+ uid integer NOT NULL default '0',
+ rid text NOT NULL default '',
+ name text NOT NULL default '',
+ preview text NOT NULL default '',
+ extra text NOT NULL default '',
+ timestamp integer NOT NULL default '0',
+ PRIMARY KEY (did)
+ )");
+ $ret[] = update_sql("CREATE INDEX deleted_uid_idx ON deleted(uid)");
+ $ret[] = update_sql("CREATE TABLE deleted_data (
+ tid SERIAL,
+ did integer NOT NULL default '0',
+ dtable text NOT NULL default '',
+ row_id integer NOT NULL default '0',
+ dcolumn text NOT NULL default '',
+ data text NOT NULL default '',
+ PRIMARY KEY (tid)
+ )");
+ $ret[] = update_sql("CREATE INDEX deleted_data_did_idx ON deleted_data(did)");
+ $ret[] = update_sql("CREATE INDEX deleted_data_dtable_idx ON deleted_data(dtable)");
+ $ret[] = update_sql("CREATE INDEX deleted_data_row_id_idx ON deleted_data(row_id)");
+ $ret[] = update_sql("CREATE INDEX deleted_data_dcolumn_idx ON deleted_data(dcolumn)");
+ break;
+ default:
+ break;
+ }
+ return $ret;
+}
=== modified file 'misc/grippie.png' (properties changed)
=== modified file 'modules/block.module'
--- modules/block.module
+++ modules/block.module
@@ -436,25 +436,18 @@ function block_box_add_submit($form_id,
}
/**
- * Menu callback; confirm deletion of custom blocks.
+ * Deletion of custom blocks.
*/
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'));
-}
-
-/**
- * Deletion of custom blocks.
- */
-function block_box_delete_confirm_submit($form_id, $form_values) {
- db_query('DELETE FROM {boxes} WHERE bid = %d', $form_values['bid']);
- drupal_set_message(t('The block %name has been removed.', array('%name' => theme('placeholder', $form_values['info']))));
+ $did = next_delete_id();
+ $preview = array('title' => $box['title'], 'info' => $box['info'], 'body' => $box['body']);
+ drupal_set_message(t('The block %name has been moved to the trash.', array('%name' => theme('placeholder', $box['info']))));
+ $trash_data = array('did' => $did, 'rid' => $bid, 'name' => 'block', 'preview' => $preview);
+ system_trash($trash_data, 'DELETE FROM {boxes} WHERE bid = %d', $bid);
cache_clear_all();
drupal_goto('admin/block');
-};
+}
function block_box_form($edit = array()) {
$form['info'] = array(
=== modified file 'modules/book.module'
--- modules/book.module
+++ modules/book.module
@@ -221,7 +221,8 @@ function book_update($node) {
* Implementation of hook_delete().
*/
function book_delete(&$node) {
- db_query('DELETE FROM {book} WHERE nid = %d', $node->nid);
+ $trash_data = array('did' => $node->did);
+ system_trash($trash_data, 'DELETE FROM {book} WHERE nid = %d', $node->nid);
}
/**
@@ -302,8 +303,11 @@ function book_outline() {
break;
case t('Remove from book outline'):
- db_query('DELETE FROM {book} WHERE nid = %d', $node->nid);
- drupal_set_message(t('The post has been removed from the book.'));
+ $did = next_delete_id();
+ $preview = array('title' => $node->title, 'body' => $node->body);
+ drupal_set_message(t('The post has been removed from the book and placed in trash.'));
+ $trash_data = array('did' => $did, 'rid' => $node->nid, 'name' => 'book', 'preview' => $preview);
+ system_trash($trash_data, 'DELETE FROM {book} WHERE nid = %d', $node->nid);
drupal_goto("node/$node->nid");
break;
@@ -469,7 +473,8 @@ function book_nodeapi(&$node, $op, $teas
}
break;
case 'delete revision':
- db_query('DELETE FROM {book} WHERE vid = %d', $node->vid);
+ $trash_data = array('did' => $node->did);
+ system_trash($trash_data, 'DELETE FROM {book} WHERE vid = %d', $node->vid);
break;
}
}
=== modified file 'modules/comment.module'
--- modules/comment.module
+++ modules/comment.module
@@ -292,8 +292,16 @@ 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);
+ $result = db_query('SELECT * FROM {comments} WHERE nid = %d', $node->nid);
+ while ($comment = db_fetch_object($result)) {
+ $i++;
+ $preview['subject'. $i] = $comment->subject;
+ $preview['comment'. $i] = $comment->comment;
+ }
+ $trash_data = array('did' => $node->did);
+ system_trash($trash_data, 'DELETE FROM {node_comment_statistics} WHERE nid = %d', $node->nid);
+ $trash_data['preview'] = $preview;
+ system_trash($trash_data, 'DELETE FROM {comments} WHERE nid = %d', $node->nid);
break;
case 'update index':
@@ -889,12 +897,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 the trash.'));
// Delete comment and its replies.
_comment_delete_thread($comment);
@@ -906,20 +912,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;
}
/**
@@ -1625,9 +1621,18 @@ function theme_comment_post_forbidden($n
}
function _comment_delete_thread($comment) {
+ static $did;
+ if ($did) {
+ $trash_data = array('did' => $did);
+ }
+ else {
+ $did = next_delete_id();
+ $preview = array('subject' => $comment->subject, 'comment' => $comment->comment);
+ $trash_data = array('did' => $did, 'rid' => $comment->nid, 'name' => 'comment', 'preview' => $preview);
+ }
// 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($trash_data, 'DELETE FROM {comments} WHERE cid = %d', $comment->cid);
+ watchdog('content', t('Comment: moved %subject to the trash.', array('%subject' => theme('placeholder', $comment->subject))));
comment_invoke_comment($comment, 'delete');
=== modified file 'modules/contact.module'
--- modules/contact.module
+++ modules/contact.module
@@ -289,21 +289,13 @@ function contact_admin_edit_submit($form
}
function contact_admin_delete($cid) {
- $info = db_fetch_object(db_query("SELECT cid, category FROM {contact} WHERE cid = %d", $cid));
- 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', $info->category))),
- 'admin/contact',
- t('This action cannot be undone.'),
- t('Delete'),
- t('Cancel')
- );
- }
- else {
- db_query("DELETE FROM {contact} WHERE cid = %d", $cid);
+ $did = next_delete_id();
+ $info = db_fetch_object(db_query("SELECT cid, category FROM {contact} WHERE cid = %d", $cid));
+ $preview = array('category' => $info->category);
+ drupal_set_message(t('Contact category %category moved to the trash', array('%category' => theme('placeholder', $info->category))));
+ $trash_data = array('did' => $did, 'rid' => $cid, 'name' => 'contact', 'preview' => $preview);
+ system_trash($trash_data, "DELETE FROM {contact} WHERE cid = %d", $cid);
drupal_goto('admin/contact');
- }
}
function contact_admin() {
=== modified file 'modules/filter.module'
--- modules/filter.module
+++ modules/filter.module
@@ -342,33 +342,25 @@ 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 = next_delete_id();
+ $preview = array('name' => $result->name);
+ drupal_set_message(t('Input format %format moved to the trash.', array('%format' => theme('placeholder', $result->name))));
+ $trash_data = array('did' => $did);
+ system_trash($trash_data, "DELETE FROM {filter_formats} WHERE format = %d", $format);
+ $trash_data = array_merge($trash_data, array('rid' => $format, 'name' => 'filter', 'preview' => $preview));
+ system_trash($trash_data, "DELETE FROM {filters} 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_goto('admin/filters');
}
/**
=== modified file 'modules/forum.module'
--- modules/forum.module
+++ modules/forum.module
@@ -77,7 +77,8 @@ function forum_perm() {
function forum_nodeapi(&$node, $op, $teaser, $page) {
switch ($op) {
case 'delete revision':
- db_query('DELETE FROM {forum} WHERE vid = %d', $node->vid);
+ $trash_data = array('did' => $node->did);
+ system_trash($trash_data, 'DELETE FROM {forum} WHERE vid = %d', $node->vid);
break;
}
}
@@ -166,7 +167,9 @@ function forum_taxonomy($op, $type, $obj
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)) {
- node_delete($node->nid);
+ $node = node_load($node->nid);
+ $node->did = $object->did;
+ node_delete($node);
}
}
elseif ($op == 'delete' && $type == 'vocabulary' && $object->vid == _forum_get_vid()) {
=== modified file 'modules/locale.module'
--- modules/locale.module
+++ modules/locale.module
@@ -301,39 +301,31 @@ 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);
-
- $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'));
+ if (isset($languages['name'][$langcode])) {
+ $did = next_delete_id();
+ $preview = array('language code' => $langcode, 'name' => $languages['name'][$langcode]);
+ $message = t('The language %locale has been moved to the trash.', array('%locale' => theme('placeholder', t($languages['name'][$langcode]))));
+ drupal_set_message($message);
+ watchdog('locale', $message);
+ $trash_data = array('did' => $did);
+ system_trash($trash_data, "DELETE FROM {locales_target} WHERE locale = '%s'", $langcode);
+ $trash_data = array_merge($trash_data, array('rid' => $langcode, 'name' => 'locale', 'preview' => $preview));
+ system_trash($trash_data, "DELETE FROM {locales_meta} WHERE locale = '%s'", $langcode);
+
+ }
+
+ // Changing the locale settings impacts the interface:
+ cache_clear_all();
+ drupal_goto('admin/locale/language/overview');
}
/**
=== modified file 'modules/node.module'
--- modules/node.module
+++ modules/node.module
@@ -864,6 +864,9 @@ function node_menu($may_cache) {
$items[] = array('path' => 'admin/node', 'title' => t('content'),
'callback' => 'node_admin_nodes',
'access' => user_access('administer nodes'));
+ $items[] = array('path' => 'admin/node/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/node/action', 'title' => t('content'),
@@ -1203,28 +1206,68 @@ function theme_node_admin_nodes($form) {
function node_multiple_delete_confirm() {
$edit = $_POST['edit'];
+ $options = array();
+ // Keep only checked node's nids
+ $nids = isset($edit['nodes']) ? array_keys($edit['nodes'], !0) : array();
+ 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.
+ $title = check_plain($node->title);
+ if (in_array(FALSE, $extras)) {
+ drupal_set_message(t('Deletion of %title cancelled', array('%title' => $title)), 'error');
+ }
+ else {
+ $form['title'][$node->nid] = array('#type' => 'markup', '#value' => $title);
+ $form['extras'][$node->nid] = $extras;
+ $options[$node->nid] = '';
+ }
+ }
+ }
+ // Back to the admin page if no nodes need confimation.
+ if (!count($options)) {
+ drupal_goto('admin/node');
+ }
+ else {
+ $form['title']['#tree'] = TRUE;
+ $form['extras']['#tree'] = TRUE;
+ $form['nodes'] = array('#type' => 'checkboxes', '#options' => $options);
+ $form['#action'] = url('admin/node/delete');
+ return confirm_form('node_multiple_delete_confirm', $form,
+ t('The following items need to be reviewed'),
+ 'admin/node', t('Selected items will be moved to the trash.'),
+ t('Delete selected'), t('Cancel'));
+ }
+}
- $form['nodes'] = array('#prefix' => '
', '#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' => '', '#suffix' => check_plain($title) ."\n");
- }
- $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
-
- return confirm_form('node_multiple_delete_confirm', $form,
- t('Are you sure you want to delete these items?'),
- 'admin/node', t('This action cannot be undone.'),
- t('Delete all'), t('Cancel'));
+function theme_node_multiple_delete_confirm($form) {
+ $rows = array();
+ $header = array('');
+ $output = '';
+ foreach(array_keys($form['nodes']['#options']) as $nid) {
+ $rows[] = array(''. ''. form_render($form['title'][$nid]) .''. form_render($form['nodes'][$nid]) .'
'. form_render($form['extras'][$nid]));
+ $rows[] = array('');
+ }
+ $output .= theme('table', $header, $rows);
+ $output .= form_render($form);
+ return $output;
}
-function node_multiple_delete_confirm_submit($form_id, $edit) {
- if ($edit['confirm']) {
- foreach ($edit['nodes'] as $nid => $value) {
- node_delete($nid);
- }
- drupal_set_message(t('The items have been deleted.'));
+function node_multiple_delete_confirm_submit($form_id, $form_values) {
+ foreach ($form_values['nodes'] as $nid => $value) {
+ // Merge extra confirm data with node
+ $node = node_load($nid);
+ $node = (array) $node;
+ $node = array_merge($node, $form_values['extras'][$nid]);
+ $node = (object) $node;
+ node_delete($node);
}
+ drupal_set_message(t('The items have been deleted.'));
drupal_goto('admin/node');
}
@@ -1343,17 +1386,19 @@ function node_revision_delete($nid, $rev
// Don't delete the current revision
if ($revision != $node->vid) {
$node = node_load($nid, $revision);
+ $did = next_delete_id();
+ $preview = array('title' => $node->title, 'body' => $node->body, 'revision' => $revision);
+
+ drupal_set_message(t('Revision %title %revision moved to the trash.', array('%title' => theme('placeholder', $node->title), '%revision' => theme('placeholder', $revision))));
+ $trash_data = array('did' => $did, 'rid' => $nid, 'name' => 'node revision', 'preview' => $preview);
+ system_trash($trash_data, "DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $nid, $revision);
- 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' => theme('placeholder', $node->title), '%revision' => theme('placeholder', $revision))));
watchdog('content', t('%type: deleted %title revision %revision.', array('%type' => theme('placeholder', t($node->type)), '%title' => theme('placeholder', $node->title), '%revision' => theme('placeholder', $revision))));
}
-
else {
drupal_set_message(t('Deletion failed. You tried to delete the current revision.'));
}
-
drupal_goto("node/$nid/revisions");
}
}
@@ -1876,18 +1921,32 @@ function node_form_submit($form_id, $edi
*/
function node_delete_confirm() {
$edit = $_POST['edit'];
- $edit['nid'] = $edit['nid'] ? $edit['nid'] : arg(1);
- $node = node_load($edit['nid']);
-
+ $nid = $edit['nid'] ? $edit['nid'] : arg(1);
+ $node = node_load($nid);
if (node_access('delete', $node)) {
$form['nid'] = array('#type' => 'value', '#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') );
+ // Check for extra info from modules
+ $extras = node_invoke_nodeapi($node, 'delete pre');
+ $form['extras'] = $extras;
+ // 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_set_message(t('Deletion cancelled'), 'error');
+ 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 move the
+ item to the trash'), t('Delete'), t('Cancel'));
+ }
+ }
}
-
- return $output;
}
/**
@@ -1895,7 +1954,12 @@ function node_delete_confirm() {
*/
function node_delete_confirm_submit($form_id, $form_values) {
if ($form_values['confirm']) {
- node_delete($form_values['nid']);
+ // Merge extra confirm data with node
+ $node = node_load($form_values['nid']);
+ $node = (array) $node;
+ $node = array_merge($node, $form_values);
+ $node = (object) $node;
+ node_delete($node);
drupal_goto();
}
}
@@ -1903,28 +1967,41 @@ function node_delete_confirm_submit($for
/**
* Delete a node.
*/
-function node_delete($nid) {
-
- $node = node_load($nid);
-
- if (node_access('delete', $node)) {
- db_query('DELETE FROM {node} WHERE nid = %d', $node->nid);
- db_query('DELETE FROM {node_revisions} WHERE nid = %d', $node->nid);
-
- // Call the node-specific callback (if any):
- node_invoke($node, 'delete');
- node_invoke_nodeapi($node, 'delete');
-
- // Clear the cache so an anonymous poster can see the node being deleted.
- cache_clear_all();
-
- // Remove this node from the search index if needed.
- if (function_exists('search_wipe')) {
- search_wipe($node->nid, 'node');
- }
- drupal_set_message(t('%title has been deleted.', array('%title' => theme('placeholder', $node->title))));
- watchdog('content', t('%type: deleted %title.', array('%type' => theme('placeholder', t($node->type)), '%title' => theme('placeholder', $node->title))));
+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 = next_delete_id();
+ $trash_data['rid'] = $node->nid;
+ $trash_data['name'] = 'node';
+ }
+ $trash_data['did'] = $node->did;
+ $preview['title'] = $node->title;
+ if ($node->body) {
+ $preview['body'] = $node->body;
+ }
+ $trash_data['preview'] = $preview;
+ drupal_set_message(t('%title moved to the trash.', array('%title' => theme('placeholder', $node->title))));
+ system_trash($trash_data, 'DELETE FROM {node} WHERE nid = %d', $node->nid);
+ $trash_data = array('did' => $node->did);
+ system_trash($trash_data, 'DELETE FROM {node_revisions} WHERE nid = %d', $node->nid);
+
+ // Call the node-specific callback (if any):
+ node_invoke($node, 'delete');
+ node_invoke_nodeapi($node, 'delete');
+
+ // Clear the cache so an anonymous poster can see the node being deleted.
+ cache_clear_all();
+
+ // Remove this node from the search index if needed.
+ if (function_exists('search_wipe')) {
+ search_wipe($node->nid, 'node');
}
+ watchdog('content', t('%type: deleted %title.', array('%type' => theme('placeholder', t($node->type)), '%title' => theme('placeholder', $node->title))));
}
/**
=== modified file 'modules/path.module'
--- modules/path.module
+++ modules/path.module
@@ -58,7 +58,7 @@ function path_menu($may_cache) {
'access' => user_access('administer url aliases'),
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/path/delete', 'title' => t('delete alias'),
- 'callback' => 'path_admin_delete_confirm',
+ 'callback' => 'path_admin_delete',
'access' => user_access('administer url aliases'),
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/path/list', 'title' => t('list'),
@@ -96,47 +96,30 @@ function path_admin_edit($pid = 0) {
}
/**
- * Menu callback; confirms deleting an URL alias
+ * Menu callback; handles deletion of an URL alias.
**/
-function path_admin_delete_confirm($pid) {
- $path = path_load($pid);
- if (user_access('administer path aliases')) {
- $form['pid'] = array('#type' => 'value', '#value' => $pid);
- $output = confirm_form('path_admin_delete_confirm', $form,
- t('Are you sure you want to delete path alias %title?', array('%title' => theme('placeholder', $path['dst']))),
- $_GET['destination'] ? $_GET['destination'] : 'admin/path', t('This action cannot be undone.'),
- t('Delete'), t('Cancel') );
- }
-
- return $output;
-}
-
-/**
- * Execute URL alias deletion
- **/
-function path_admin_delete_confirm_submit($form_id, $form_values) {
- if ($form_values['confirm']) {
- path_admin_delete($form_values['pid']);
- drupal_goto('admin/path');
- }
-}
-
-/**
- * Post-confirmation; delete 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 = next_delete_id();
+ $result = db_fetch_object(db_query('SELECT src, dst FROM {url_alias} WHERE pid = %d', $pid));
+ $preview = array('source' => $result->src, 'destination' => $result->dst);
+ drupal_set_message(t('The alias has been moved to the trash.'));
+ $trash_data = array('did' => $did, 'rid' => $pid, 'name' => 'url alias', 'preview' => $preview);
+ system_trash($trash_data, 'DELETE FROM {url_alias} WHERE pid = %d', $pid);
+ 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) {
+ $trash_data = array('did' => $node->did);
+ system_trash($trash_data, "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) {
@@ -235,7 +218,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;
}
=== modified file 'modules/poll.module'
--- modules/poll.module
+++ modules/poll.module
@@ -84,10 +84,20 @@ 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);
- db_query("DELETE FROM {poll_votes} WHERE nid = %d", $node->nid);
+function poll_delete(&$node) {
+ // Poll trash preview
+ $preview = array();
+ if ($node->choice) {
+ foreach ($node->choice as $key => $array) {
+ $c++;
+ $preview["choice$c"] = $array['chtext'];
+ }
+ }
+ $trash_data = array('did' => $node->did);
+ system_trash($trash_data, "DELETE FROM {poll_choices} WHERE nid = %d", $node->nid);
+ system_trash($trash_data, "DELETE FROM {poll_votes} WHERE nid = %d", $node->nid);
+ $trash_data = array_merge($trash_data, array('preview' => $preview));
+ system_trash($trash_data, "DELETE FROM {poll} WHERE nid = %d", $node->nid);
}
/**
=== modified file 'modules/profile.module'
--- modules/profile.module
+++ modules/profile.module
@@ -548,22 +548,17 @@ 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);
- db_query('DELETE FROM {profile_values} 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('Are you sure you want to delete the field %field?', array('%field' => theme('placeholder', $field->title))),
- 'admin/settings/profile',
- t('This action cannot be undone. If users have entered values into this field in their profile, these entries will also be deleted. If you want to keep the user-entered data, instead of deleting the field you may wish to edit this field and change it to a \'hidden profile field\' so that it may only be accessed by administrators.', array('%edit-field' => url('admin/settings/profile/edit/' . $fid))),
- t('Delete'),
- t('Cancel'));
- }
+ $did = next_delete_id();
+ $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);
+ drupal_set_message(t('The field %field has been moved to the trash. If users have entered values into this field in their profile, these entries have also been moved to the trash. If you want to keep the user-entered data, instead of deleting the field you may wish to restore it and edit the field, changing it to a \'hidden profile field\' so that it may only be accessed by administrators.', array('%field' => theme('placeholder', $result->title), '%edit-field' => url('admin/settings/profile/edit/' . $fid))));
+ $trash_data = array('did' => $did);
+ system_trash($trash_data, 'DELETE FROM {profile_values} WHERE fid = %d', $fid);
+ $trash_data = array_merge($trash_data, array('rid' => $fid, 'name' => 'profile', 'preview' => $preview));
+ system_trash($trash_data, 'DELETE FROM {profile_fields} WHERE fid = %d', $fid);
+
+ cache_clear_all();
+ drupal_goto('admin/settings/profile');
}
function _profile_field_form($type, $edit = array()) {
=== modified file 'modules/statistics.module'
--- modules/statistics.module
+++ modules/statistics.module
@@ -477,7 +477,8 @@ 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);
+ $trash_data = array('did' => $node->did);
+ system_trash($trash_data, 'DELETE FROM {node_counter} WHERE nid = %d', $node->nid);
}
}
=== modified file 'modules/system.module'
--- modules/system.module
+++ modules/system.module
@@ -47,7 +47,7 @@ function system_help($section) {
* Implementation of hook_perm().
*/
function system_perm() {
- return array('administer site configuration', 'access administration pages', 'select different theme');
+ return array('administer site configuration', 'administer trash', 'access administration pages', 'select different theme');
}
/**
@@ -92,6 +92,7 @@ function system_elements() {
* Implementation of hook_menu().
*/
function system_menu($may_cache) {
+ global $user;
$items = array();
if ($may_cache) {
@@ -146,6 +147,14 @@ 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->uid != 0);
+ $items[] = array('path' => 'trash/preview', 'title' => t('preview'),
+ 'callback' => 'system_trash_preview', 'access' => $user->uid != 0, 'type' => MENU_CALLBACK);
+ $items[] = array('path' => 'trash/recover', 'title' => t('recover'),
+ 'callback' => 'system_trash_recover_single', 'access' => $user->uid != 0, 'type' => MENU_CALLBACK);
}
return $items;
@@ -1220,6 +1229,435 @@ function theme_search_box($form) {
return $output;
}
+function system_admin_trash() {
+ global $user;
+ $op = $_POST['op'];
+ if ($op && ($op != t('Recover'))) {
+ return system_trash_delete_confirm();
+ }
+ $form = array();
+ $view_all = user_access('administer trash');
+ if ($view_all) {
+ $result = pager_query("SELECT * FROM {deleted} ORDER BY timestamp DESC", 25 , 0);
+ }
+ else {
+ $result = pager_query("SELECT * FROM {deleted} WHERE uid = %d ORDER BY timestamp DESC", 25 , 0, NULL, $user->uid);
+ }
+ $destination = drupal_get_destination();
+ $form = array();
+ while ($recover = db_fetch_object($result)) {
+ $preview = unserialize($recover->preview);
+ $title = is_array($preview[0]) ? array_shift($preview[0]) : '[none]';
+ $items[$recover->did] = '';
+ $form['datetime'][$recover->did] = array('#type' => 'markup', '#value' => format_date($recover->timestamp, 'small'));
+ $form['type'][$recover->did] = array('#type' => 'markup', '#value' => t($recover->name));
+ $form['title'][$recover->did] = array('#type' => 'markup', '#value' => t($title));
+ $form['preview'][$recover->did] = array('#type' => 'markup', '#value' => l(t('preview'), "trash/preview/$recover->did", array(), $destination));
+ }
+ // Build form only if items exist
+ if (isset($form['datetime'])) {
+ $form['dids'] = array('#type' => 'checkboxes', '#options' => $items);
+ $form['pager'] = array('#value' => theme('pager', NULL, 25, 0));
+ $form['buttons'] = array('#prefix' => '', '#suffix' => '
');
+ $form['buttons']['recover'] = array('#type' => 'submit', '#value' => t('Recover'));
+ if ($view_all) {
+ $form['buttons']['delete'] = array('#type' => 'submit', '#value' => t('Delete selected'));
+ $form['buttons']['delete_all'] = array('#type' => 'submit', '#value' => t('Delete all'));
+ }
+ }
+
+
+ return drupal_get_form('system_admin_trash', $form);
+}
+
+function theme_system_admin_trash($form) {
+
+ // Overview table:
+ if (is_array($form['datetime'])) {
+ $output = form_render($form['buttons']);
+ $header = array(NULL, t('Title'), t('Type'), t('Trashed'), t('Operations'));
+ foreach (element_children($form['datetime']) as $key) {
+ $row = array();
+ $row[] = form_render($form['dids'][$key]);
+ $row[] = form_render($form['title'][$key]);
+ $row[] = form_render($form['type'][$key]);
+ $row[] = form_render($form['datetime'][$key]);
+ $row[] = form_render($form['preview'][$key]);
+ $rows[] = $row;
+ }
+ $output .= theme('table', $header, $rows);
+ if ($form['pager']['#value']) {
+ $output .= form_render($form['pager']);
+ }
+ }
+ elseif (arg(1) != 'preview') {
+ $output = t('There are no items in your trash');
+ }
+
+ $output .= form_render($form);
+
+ return $output;
+}
+
+function system_trash($trash_data, $query) {
+ global $user;
+ static $same_did;
+ static $rid;
+ static $name;
+ static $summed_preview;
+ static $extra;
+ // Grab the args for the query
+ $all_args = func_get_args();
+ if (count($all_args) > 2) {
+ $args = array_slice($all_args, 2);
+ }
+ else {
+ $args = array();
+ }
+ // Turn delete into select and get result
+ $delete = preg_replace('/DELETE.*?FROM/i', 'SELECT * FROM', $query);
+ $result = db_query($delete, $args);
+ $did = $trash_data['did'];
+ // For rid and name, give trash_data precedence, then existing value, then wipe value if did has changed
+ $rid = $trash_data['rid'] ? $trash_data['rid'] : ($same_did == $did ? $rid : '');
+ $name = $trash_data['name'] ? $trash_data['name'] : ($same_did == $did ? $name : '');
+ // Grab table name and store
+ $table = preg_match('/^DELETE FROM \{([^}]+)/', $query, $m);
+ $table = $m[1];
+ // Loop through result inserting rows into deleted_data table
+ while ($data = db_fetch_array($result)) {
+ $row_id = db_next_id('{deleted_data}_row_id');
+ foreach ($data as $column => $value) {
+ $tid = db_next_id('{deleted_data}_tid');
+ db_query("INSERT INTO {deleted_data} VALUES(%d, %d, '%s', %d, '%s', '%s')", $tid, $did, $table, $row_id, $column, $value);
+ }
+ }
+ // Only one message for each did
+ if ($same_did != $did) {
+ drupal_set_message(t('You may %recover the item from the %trash.', array('%recover' => l(t('recover'), "trash/recover/$did"), '%trash' => l(t('trash'), "admin/trash"))));
+
+ // Allow modules to add extra metadata
+ $extra = serialize(module_invoke_all('system_trash', $trash_data));
+
+ $same_did = $did;
+ $summed_preview = array();
+
+ }
+ // Insert new preview summary and extra data
+ if ($trash_data['preview']) {
+ $summed_preview[] = $trash_data['preview'];
+ }
+ $insert_preview = $summed_preview ? serialize($summed_preview) : '';
+ if (db_num_rows(db_query('SELECT did FROM {deleted} WHERE did = %d', $did))) {
+ db_query("UPDATE {deleted} SET rid = '%s', name = '%s', preview = '%s', extra = '%s' WHERE did = %d", $rid, $name, $insert_preview, $extra, $did);
+ }
+ else {
+ db_query("INSERT INTO {deleted} VALUES(%d, %d, '%s', '%s', '%s', '%s', %d)", $did, $user->uid, $rid, $name, $insert_preview, $extra, time());
+ }
+ // Delete from original table
+ db_query($query, $args);
+}
+
+function system_trash_preview($did) {
+ global $user;
+ $op = $_POST['op'];
+ $view_all = user_access('administer trash');
+ $insert = db_fetch_object(db_query('SELECT * FROM {deleted} WHERE did = %d', $did));
+ if ($view_all || $insert->uid == $user->uid) {
+ if ($op == t('Delete')) {
+ return system_trash_delete_confirm();
+ }
+ $output = '';
+ $form['buttons'] = array('#prefix' => '', '#suffix' => '
');
+ $form['buttons']['recover'] = array('#type' => 'submit', '#value' => t('Recover'));
+ if ($view_all) {
+ $form['buttons']['delete'] = array('#type' => 'button', '#button_type' => 'submit', '#value' => t('Delete'));
+ }
+
+ $form['dids']['#tree'] = TRUE;
+ $form['dids'][$did] = array('#type' => 'hidden', '#value' => $did);
+
+ $output .= drupal_get_form('system_trash_preview', $form, 'system_admin_trash');
+
+ // Grab preview data
+ $values = array();
+ $data = $insert->preview ? unserialize($insert->preview) : array();
+ if ($data) {
+ $title = array_shift($data[0]);
+ drupal_set_title(t('Preview: %title (trashed)', array('%title' => filter_xss($title))));
+ }
+ $header = array();
+ $rows = array();
+ foreach ($data as $preview_section) {
+ foreach ($preview_section as $key => $value) {
+ $rows[] = array(''. t($key) . ': ', filter_xss($value));
+ }
+ $rows[] = array(array('data' => '', 'colspan' => 2));
+ }
+ $output .= '';
+ $output .= '- '. t('Trashed') .': '. format_date($insert->timestamp, 'small');
+ $output .= '
- '. t('Type') .': '. t($insert->name);
+ $output .= '
';
+ $output .= ''. t('Data') .':
';
+ $output .= theme('table', $header, $rows);;
+ return $output;
+ }
+ else {
+ drupal_access_denied();
+ }
+}
+
+function system_trash_recover($dids) {
+ $nid = NULL;
+ $single_item = (count($dids) == 1);
+ $all_dids = implode(', ', $dids);
+ $result = db_query("SELECT * FROM {deleted_data} WHERE did IN(%s)", $all_dids);
+ while ($row = db_fetch_array($result)) {
+ $all_data[$row['did']][$row['row_id']][] = $row;
+ }
+ $recover_data = system_trash_dependency_check($all_data);
+ if ($recover_data) {
+ foreach ($recover_data as $did => $rows) {
+ foreach ($rows as $data) {
+ $table = $data[0]['dtable'];
+ $fields = array();
+ $values = array();
+ $data_values = array();
+ foreach ($data as $value) {
+ $fields[] = $value['dcolumn'];
+ $values[] = is_numeric($value['data']) ? '%d' : "'%s'";
+ $data_values[$value['dcolumn']] = $value['data'];
+ // Best guess at recovered node if present
+ if ($value['dcolumn'] == 'nid' && $single_item) {
+ $nid = $value['data'];
+ }
+ }
+ $query_fields = implode(', ', $fields);
+ $query_values = implode(', ', $values);
+ $args = array_merge(array($table), array($query_fields), $data_values);
+ db_query('INSERT INTO {%s} (%s) VALUES('. $query_values .')', $args);
+ }
+ $delete_dids[] = $did;
+ $trash_data = db_fetch_array(db_query('SELECT * FROM {deleted} WHERE did = %d', $did));
+ $trash_data['extra'] = $trash_data['extra'] ? unserialize($trash_data['extra']) : array();
+ module_invoke_all('system_trash_recover', $trash_data);
+ }
+ $delete_dids_query = implode(', ', $delete_dids);
+ db_query('DELETE FROM {deleted} WHERE did IN(%s)', $delete_dids_query);
+ db_query('DELETE FROM {deleted_data} WHERE did IN(%s)', $did);
+ }
+ return $nid;
+}
+
+function system_trash_dependency_check($recover_data) {
+
+ // Check package for dependency conflicts
+ $dids = array_keys($recover_data);
+ foreach ($recover_data as $did => $rows) {
+ foreach ($rows as $row => $data) {
+ $table = $data[0]['dtable'];
+ if (!system_trash_check_row_dependency($table, $data, $dids)) {
+ $recover = FALSE;
+ $package = db_fetch_object(db_query('SELECT preview FROM {deleted} WHERE did = %d', $did));
+ $preview = $package->preview ? unserialize($package->preview) : array();
+ if ($preview) {
+ $title = array_shift($preview[0]);
+ }
+ else {
+ $title = t('[untitled]');
+ }
+ drupal_set_message(t('%title cannot be recovered due to dependency errors. Check the errors and recover any data this
+ package depends on before attempting recovery.', array('%title' => theme('placeholder', $title))), 'error');
+ unset($recover_data[$data[0]['did']]);
+ return system_trash_dependency_check($recover_data);
+ }
+ }
+ }
+ return $recover_data;
+}
+
+function system_trash_check_row_dependency($table, $data, $dids) {
+
+ $return = TRUE;
+ $dependencies = system_get_dependencies($table);
+ foreach ($dependencies as $dependency) {
+ $value = NULL;
+ $dependency[3] = isset($dependency[3]) ? $dependency[3] : array();
+ foreach ($data as $array) {
+ if ($array['dcolumn'] == $dependency[0]) {
+ $value = $array['data'];
+ }
+ }
+ if (!isset($value)) {
+ $return = FALSE;
+ drupal_set_message(t('Dependency error: no matching key %key in table %table. Dependency of table %dependency', array('%key' => $dependency[0],
+ '%table' => $table, '%dependency' => $dependency[2])), 'error');
+ }
+ else {
+ if (!system_check_dependency($dependency, $value) && !system_check_package_dependencies($dependency, $value, $dids) && !in_array($value, $dependency[3])) {
+ $return = FALSE;
+ drupal_set_message(t("Dependency error: value '%value' for key '%key' missing in table %dependency", array('%value' => $value,
+ '%key' => $dependency[1], '%dependency' => $dependency[2])), 'error');
+ }
+ }
+ }
+ return $return;
+}
+
+function system_check_package_dependencies($dependency, $value, $dids) {
+ $field = $dependency[1];
+ $table = $dependency[2];
+ $dids_query = implode(', ', $dids);
+ return db_num_rows(db_query("SELECT * FROM {deleted_data} WHERE dtable = '%s' AND dcolumn = '%s' AND data = '%s' AND did IN(%s)",
+ $table, $field, $value, $dids_query));
+
+}
+
+function system_trash_recover_single($did) {
+ if (user_access('administer trash') || $user->uid == db_result(db_query('SELECT uid FROM {deleted} WHERE did = %d', $did))) {
+ $nid = system_trash_recover(array($did));
+ drupal_set_message(t('The item has been recovered'));
+ if ($nid = db_result(db_query('SELECT nid FROM {node} WHERE nid = %d', $nid))) {
+ drupal_goto("node/$nid");
+ }
+ else {
+ drupal_goto();
+ }
+ }
+ else {
+ drupal_access_denied();
+ }
+}
+
+function system_admin_trash_submit($form_id, $form_values) {
+ $dids = $form_values['dids'] ? array_keys($form_values['dids'], !0) : array();
+ if ((count($dids) == 0)) {
+ drupal_set_message(t('No items were selected. Select items in order to perform the operation'));
+ drupal_goto('admin/trash');
+ }
+ $nid = system_trash_recover($dids);
+ $message = $nid ? t('The %item has been recovered', array('%item' => l(t('item'), "node/$nid"))) : t('The items have been recovered');
+
+ drupal_set_message($message);
+ drupal_goto('admin/trash');
+}
+
+function system_trash_delete($did) {
+ $trash_data = db_fetch_array(db_query('SELECT * FROM {deleted} WHERE did = %d', $did));
+ $trash_data['extra'] = $trash_data['extra'] ? unserialize($trash_data['extra']) : array();
+ module_invoke_all('system_trash_delete', $trash_data);
+ db_query('DELETE FROM {deleted} WHERE did = %d', $did);
+ db_query('DELETE FROM {deleted_data} WHERE did = %d', $did);
+}
+
+function system_trash_delete_confirm_submit($form_id, $form_values) {
+ if (isset($form_values['dids'])) {
+ foreach ($form_values['dids'] as $did) {
+ system_trash_delete($did);
+ }
+ }
+ else {
+ $dids = db_query('SELECT did FROM {deleted}');
+ while ($did = db_fetch_object($dids)) {
+ $did = $did->did;
+ system_trash_delete($did);
+ }
+ }
+ drupal_set_message(t('Permanent delete successful'));
+ drupal_goto('admin/trash');
+}
+
+function system_trash_delete_confirm() {
+ $dids = $_POST['edit']['dids'] ? array_keys($_POST['edit']['dids'], !0) : array();
+ if ((count($dids) == 0) && $_POST['op'] == t('Delete selected')) {
+ drupal_set_message(t('No items were selected. Select items in order to perform the operation'));
+ drupal_goto('admin/trash');
+ }
+ $form['dids']['#tree'] = TRUE;
+ foreach ($dids as $did) {
+ $form['dids'][$did] = array('#type' => 'hidden', '#value' => $did);
+ }
+ $output = confirm_form('system_trash_delete_confirm', $form,
+ t('Are you sure you want to permanently delete these items?'),
+ 'admin/trash', t('This operation cannot be undone.'),
+ t('Delete'), t('Cancel'));
+ return $output;
+}
+
+function next_delete_id() {
+ return db_next_id('{deleted}_did');
+}
+
+function system_table_dependencies() {
+ $dependencies = array();
+ $dependencies['accesslog'] = array(array('sid', 'sid', 'sessions'), array('uid', 'uid', 'users'));
+ $dependencies['aggregator_category_feed'] = array(array('cid', 'cid', 'aggregator_category'));
+ // NEED TO FIGURE OUT THE OTHER AGGREGATOR TABLE RELATIONSHIPS
+ $dependencies['authmap'] = array(array('uid', 'uid', 'users')); //AID RELATED TO ANYTHING?
+ $dependencies['book'] = array(array('vid', 'vid', 'node_revisions'), array('nid', 'nid', 'node'));
+ $dependencies['comments'] = array(array('uid', 'uid', 'users'), array('nid', 'nid', 'node'), array('pid', 'cid', 'comments', array(0)));
+ $dependencies['files'] = array(array('nid', 'nid', 'node'), array('vid', 'vid', 'node_revisions'));
+ $dependencies['filters'] = array(array('format', 'format', 'filter_formats'));
+ $dependencies['forum'] = array(array('nid', 'nid', 'node'), array('vid', 'vid', 'node_revisions'), array('tid', 'tid', 'term_data'));
+ $dependencies['history'] = array(array('uid', 'uid', 'users'), array('nid', 'nid', 'node_revisions'));
+ // LOCALES TABLES NEED ENTERED HERE
+ $dependencies['menu'] = array(array('pid', 'mid', 'menu'));
+ $dependencies['moderation_roles'] = array(array('rid', 'rid', 'role'), array('mid', 'mid', 'moderation_votes'));
+ $dependencies['node'] = array(array('vid', 'vid', 'node_revisions'), array('uid', 'uid', 'users'));
+ $dependencies['node_access'] = array(array('nid', 'nid', 'node')); // GID RELATED TO ANYTHING?
+ $dependencies['node_comment_statistics'] = array(array('nid', 'nid', 'node'), array('last_comment_uid', 'uid', 'users'));
+ $dependencies['node_counter'] = array(array('nid', 'nid', 'node'));
+ $dependencies['node_revisions'] = array(array('nid', 'nid', 'node'), array('uid', 'uid', 'users'));
+ $dependencies['permission'] = array(array('rid', 'rid', 'role'));
+ $dependencies['poll'] = array(array('nid', 'nid', 'node'));
+ $dependencies['poll_choices'] = array(array('nid', 'nid', 'node'));
+ $dependencies['profile_values'] = array(array('fid', 'fid', 'profile_fields'), array('uid', 'uid', 'users'));
+ // SEARCH TABLES HERE
+ $dependencies['sessions'] = array(array('uid', 'uid', 'users')); // SID RELATED TO ANYTHING?
+ $dependencies['term_data'] = array(array('vid', 'vid', 'vocabulary'));
+ $dependencies['term_hierarchy'] = array(array('tid', 'tid', 'term_data'), array('parent', 'tid', 'term_hierarchy'));
+ $dependencies['term_node'] = array(array('nid', 'nid', 'node'), array('tid', 'tid', 'term_data'));
+ $dependencies['term_relation'] = array(array('tid1', 'tid', 'term_data'), array('tid2', 'tid', 'term_data'));
+ $dependencies['term_synonym'] = array(array('tid', 'tid', 'term_data'));
+ $dependencies['users_roles'] = array(array('uid', 'uid', 'users'), array('rid', 'rid', 'role'));
+ $dependencies['vocabulary_node_types'] = array(array('vid', 'vid', 'vocabulary')); //TYPE RELATED TO ANYTHING?
+ $dependencies['watchdog'] = array(array('uid', 'uid', 'users'));
+
+ return $dependencies;
+}
+
+function system_build_dependencies() {
+ static $dependencies;
+
+ if (!isset($dependencies)) {
+ // Build dependencies array
+ $dependencies = module_invoke_all('table_dependencies');
+ }
+ return $dependencies;
+}
+
+function system_get_dependencies($table) {
+ $dependencies = system_build_dependencies();
+ if (array_key_exists($table, $dependencies)) {
+ return $dependencies[$table];
+ }
+ else {
+ return array();
+ }
+}
+
+function system_check_dependency($dependency, $value) {
+ $field = $dependency[1];
+ $table = $dependency[2];
+ if (is_numeric($value)) {
+ $result = db_num_rows(db_query('SELECT * FROM {%s} WHERE %s = %d', $table, $field, $value));
+ }
+ else {
+ $result = db_num_rows(db_query("SELECT * FROM {%s} WHERE %s = '%s'", $table, $field, $value));
+ }
+ return $result;
+}
+
/**
* Output a confirmation form
*
=== modified file 'modules/taxonomy.module'
--- modules/taxonomy.module
+++ modules/taxonomy.module
@@ -171,13 +171,19 @@ function taxonomy_save_vocabulary(&$edit
function taxonomy_del_vocabulary($vid) {
$vocabulary = (array) 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 = next_delete_id();
+ $preview = array('name' => $vocabulary['name'], 'description' => $vocabulary['description']);
+ $trash_data = array('did' => $did);
+ system_trash($trash_data, 'DELETE FROM {vocabulary_node_types} WHERE vid = %d', $vid);
+ $trash_data = array_merge($trash_data, array('rid' => $vid, 'name' => 'vocabulary', 'preview' => $preview));
+ system_trash($trash_data, 'DELETE FROM {vocabulary} 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);
+ taxonomy_del_term($term->tid, $did);
}
+ $vocabulary['did'] = $did;
module_invoke_all('taxonomy', 'delete', 'vocabulary', $vocabulary);
cache_clear_all();
@@ -185,20 +191,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);
@@ -315,7 +307,14 @@ function taxonomy_save_term(&$edit) {
return $status;
}
-function taxonomy_del_term($tid) {
+function taxonomy_del_term($tid, $vocab_did = NULL) {
+ static $count;
+ if ($vocab_did) {
+ $did = $vocab_did;
+ }
+ else {
+ $did = next_delete_id();
+ }
$tids = array($tid);
while ($tids) {
$children_tids = $orphans = array();
@@ -332,37 +331,38 @@ function taxonomy_del_term($tid) {
}
$term = (array) 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) {
+ $preview = array('root term' => $term['name'], 'description' => $term['description']);
+ $trash_data = array('did' => $did, 'rid' => $term['vid'], 'name' => 'taxonomy term', 'preview' => $preview);
+ $recurse = 1;
+ }
+ else {
+ $count++;
+ $preview = array();
+ if ($term['name']) {
+ $preview['term'. $count] = $term['name'];
+ }
+ if ($term['description']) {
+ $preview['description'. $count] = $term['description'];
+ }
+ $trash_data = array('did' => $did, 'preview' => $preview);
+ }
+ drupal_set_message(t('Moved term %name to the trash.', array('%name' => theme('placeholder', $term['name']))));
+ system_trash($trash_data, 'DELETE FROM {term_data} WHERE tid = %d', $tid);
+ system_trash($trash_data, 'DELETE FROM {term_hierarchy} WHERE tid = %d', $tid);
+ system_trash($trash_data, 'DELETE FROM {term_relation} WHERE tid1 = %d OR tid2 = %d', $tid, $tid);
+ system_trash($trash_data, 'DELETE FROM {term_synonym} WHERE tid = %d', $tid);
+ system_trash($trash_data, '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']))));
}
$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'));
-}
-
/**
* Generate a tabular listing of administrative functions for vocabularies.
*/
@@ -591,7 +591,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.
@@ -652,13 +652,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') {
@@ -1019,7 +1012,8 @@ function taxonomy_nodeapi($node, $op, $a
taxonomy_node_save($node->nid, $node->taxonomy);
break;
case 'delete':
- taxonomy_node_delete($node->nid);
+ $trash_data = array('did' => $node->did);
+ system_trash($trash_data, 'DELETE FROM {term_node} WHERE nid = %d', $node->nid);
break;
case 'validate':
taxonomy_node_validate($node);
@@ -1136,20 +1130,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)) {
@@ -1160,7 +1143,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 the trash.', array('%name' => theme('placeholder', $deleted_name))));
break;
}
}
=== modified file 'modules/upload.module'
--- modules/upload.module
+++ modules/upload.module
@@ -317,17 +317,25 @@ function upload_nodeapi(&$node, $op, $ar
}
break;
case 'delete revision':
- $node->files = upload_load($node);
- foreach ($node->files as $file) {
- // Check any other revisions pointing to file first.
+ $file_info = upload_load($node);
+ foreach ($file_info as $file) {
+ // Add preview for only those files associated with this single revision
if( db_result(db_query("SELECT COUNT(fid) FROM {files} WHERE fid = %d", $file->fid)) == 1 ) {
- file_delete($file->filepath);
+ $i++;
+ $preview['file'. $i] = $file->filename;
}
}
- db_query("DELETE FROM {files} WHERE vid = %d", $node->vid);
+ $trash_data = array('did' => $node->did, 'preview' => $preview);
+ system_trash($trash_data, "DELETE FROM {files} WHERE vid = %d", $node->vid);
break;
case 'delete':
- upload_delete($node);
+ $file_info = upload_load($node);
+ foreach ($file_info as $file) {
+ $i++;
+ $preview['file'. $i] = $file->filename;
+ }
+ $trash_data = array('did' => $node->did, 'preview' => $preview);
+ system_trash($trash_data, "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;
@@ -426,14 +434,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) {
$header = array(t('Delete'), t('List'), t('Description'), t('Size'));
$rows = array();
@@ -546,3 +546,31 @@ function upload_js() {
print drupal_call_js('window.parent.iframeHandler', $output);
exit;
}
+
+function upload_system_trash($trash_data) {
+ // Store file info in case of later permanent deletion
+ $rid = $trash_data['rid'];
+ if (($trash_data['name'] == 'node') && isset($rid)) {
+ $node = node_load($rid);
+ $file_info = upload_load($node);
+ $files = array();
+ foreach ($file_info as $fid => $file) {
+ $filepaths[$fid] = $file->filepath;
+ }
+ $recover['files'] = $filepaths;
+ return $recover;
+ }
+}
+
+function upload_system_trash_delete($trash_data) {
+ // Permanently delete associated files
+ $files = $trash_data['extra']['files'];
+ if ($files) {
+ foreach ($files as $fid => $filepath) {
+ // Check any other revisions pointing to file first.
+ if (db_result(db_query("SELECT COUNT(fid) FROM {files} WHERE fid = %d", $fid)) == 0) {
+ file_delete($filepath);
+ }
+ }
+ }
+}
=== modified file 'modules/user.module'
--- modules/user.module
+++ modules/user.module
@@ -1258,19 +1258,19 @@ function user_edit($category = 'account'
$edit = $_POST['op'] ? $_POST['edit'] : (array)$account;
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);
- watchdog('user', t('Deleted user: %name %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', '<'. $account->mail .'>'))), WATCHDOG_NOTICE);
- 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 = next_delete_id();
+ $preview = array('name' => $account->name, 'email' => $account->mail);
+ drupal_set_message(t('The account has been moved to the trash.'));
+ db_query('DELETE FROM {sessions} WHERE uid = %d', $account->uid);
+ $trash_data = array('did' => $did);
+ system_trash($trash_data, 'DELETE FROM {users_roles} WHERE uid = %d', $account->uid);
+ system_trash($trash_data, 'DELETE FROM {authmap} WHERE uid = %d', $account->uid);
+ $trash_data = array_merge($trash_data, array('rid' => $account->uid, 'name' => 'user', 'preview' => $preview));
+ system_trash($trash_data, 'DELETE FROM {users} WHERE uid = %d', $account->uid);
+ watchdog('user', t('Deleted user: %name %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', '<'. $account->mail .'>'))), WATCHDOG_NOTICE);
+ $account->did = $did;
+ module_invoke_all('user', 'delete', $edit, $account);
+ drupal_goto('admin/user');
}
else if ($_POST['op'] == t('Delete')) {
if ($_REQUEST['destination']) {
@@ -1468,21 +1468,11 @@ 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_submit($form_id, $edit) {
- db_query('DELETE FROM {access} WHERE aid = %d', $edit['aid']);
+ $did = next_delete_id();
+ $preview = array('type' => $access_types[$edit->type], 'rule' => $edit->mask);
drupal_set_message(t('The access rule has been deleted.'));
+ $trash_data = array('did' => $did, 'rid' => $aid, 'name' => 'access rule', 'preview' => $preview);
+ system_trash($trash_data, 'DELETE FROM {access} WHERE aid = %d', $aid);
drupal_goto('admin/access/rules');
}
@@ -1711,8 +1701,13 @@ 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 = next_delete_id();
+ $preview = db_fetch_array(db_query('SELECT name FROM {role} WHERE rid = %d', $id));
+ drupal_set_message(t('The role has been moved to the trash. All users with only this role have been moved to the authenticated users pool.'));
+ $trash_data = array('did' => $did);
+ system_trash($trash_data, 'DELETE FROM {permission} WHERE rid = %d', $id);
+ $trash_data = array_merge($trash_data, array('rid' => $id, 'name' => 'role', 'preview' => $preview));
+ system_trash($trash_data, 'DELETE FROM {role} 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);
@@ -1723,10 +1718,10 @@ function user_admin_role() {
}
if ($uid) {
- db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
+ $trash_data = array('did' => $did);
+ system_trash($trash_data, 'DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
}
- drupal_set_message(t('The role has been deleted.'));
drupal_goto('admin/access/roles');
}
else if ($op == t('Add role')) {
=== modified file 'update.php'
--- update.php
+++ update.php
@@ -359,6 +359,7 @@ function update_selection_page() {
}
function update_update_page() {
+
// Set the installed version so updates start at the correct place.
$_SESSION['update_remaining'] = array();
foreach ($_POST['edit']['start'] as $module => $version) {
@@ -463,6 +464,9 @@ function update_progress_page_nojs() {
}
function update_finished_page() {
+
+ // The deleted table is cleared here to prevent stale data from being reinserted between db updates
+ db_query('DELETE FROM {deleted}');
drupal_set_title('Drupal database update');
// NOTE: we can't use l() here because the URL would point to 'update.php?q=admin'.
$links[] = 'main page';