Index: modules/user/user.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v
retrieving revision 1.63
diff -u -p -r1.63 user.admin.inc
--- modules/user/user.admin.inc 6 Jul 2009 19:07:21 -0000 1.63
+++ modules/user/user.admin.inc 7 Jul 2009 05:54:11 -0000
@@ -126,7 +126,6 @@ function user_filter_form_submit($form,
* @see user_admin_account_submit()
*/
function user_admin_account() {
-
$header = array(
array(),
array('data' => t('Username'), 'field' => 'u.name'),
@@ -195,7 +194,7 @@ function user_admin_account() {
}
$form['accounts'] = array(
'#type' => 'checkboxes',
- '#options' => $accounts
+ '#options' => $accounts,
);
$form['pager'] = array('#markup' => theme('pager', NULL));
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.1008
diff -u -p -r1.1008 user.module
--- modules/user/user.module 5 Jul 2009 18:07:04 -0000 1.1008
+++ modules/user/user.module 7 Jul 2009 05:54:12 -0000
@@ -2263,46 +2263,67 @@ function user_multiple_role_edit($accoun
function user_multiple_cancel_confirm(&$form_state) {
$edit = $form_state['input'];
- $form['accounts'] = array('#prefix' => '
', '#tree' => TRUE);
- // array_filter() returns only elements with TRUE values.
- foreach (array_filter($edit['accounts']) as $uid => $value) {
- $user = db_query('SELECT name FROM {users} WHERE uid = :uid', array(':uid' => $uid))->fetchField();
- $form['accounts'][$uid] = array('#type' => 'hidden', '#value' => $uid, '#prefix' => '', '#suffix' => check_plain($user) . "\n");
- }
-
- $form['operation'] = array('#type' => 'hidden', '#value' => 'cancel');
-
- module_load_include('inc', 'user', 'user.pages');
- $form['user_cancel_method'] = array(
- '#type' => 'item',
- '#title' => t('When cancelling these accounts'),
- );
- $form['user_cancel_method'] += user_cancel_methods();
- // Remove method descriptions.
- foreach (element_children($form['user_cancel_method']) as $element) {
- unset($form['user_cancel_method'][$element]['#description']);
- }
+ // Remove uid1 from the $accounts array so it can't be accidentally deleted.
+ // This should have been prevented by JS, so this is just a failsafe check.
+ if ($edit['accounts'] && array_key_exists(1, $edit['accounts'])) {
+ $user1 = user_load(1);
+ unset($edit['accounts'][1]);
+ drupal_set_message(t('You attempted to cancel the %user1 account which might have broken your site; that part of the request has been disallowed.', array('%user1' => check_plain($user1->name))), 'warning');
+ }
+
+ if (count($edit['accounts']) > 0) {
+ $form['accounts'] = array('#prefix' => '', '#tree' => TRUE);
+ // array_filter() returns only elements with TRUE values.
+ foreach (array_filter($edit['accounts']) as $uid => $value) {
+ $user = db_query('SELECT name FROM {users} WHERE uid = :uid', array(':uid' => $uid))->fetchField();
+ $form['accounts'][$uid] = array('#type' => 'hidden', '#value' => $uid, '#prefix' => '', '#suffix' => check_plain($user) . "\n");
+ }
+
+ $form['operation'] = array('#type' => 'hidden', '#value' => 'cancel');
+
+ module_load_include('inc', 'user', 'user.pages');
+ $form['user_cancel_method'] = array(
+ '#type' => 'item',
+ '#title' => t('When cancelling these accounts'),
+ );
+ $form['user_cancel_method'] += user_cancel_methods();
+ // Remove method descriptions.
+ foreach (element_children($form['user_cancel_method']) as $element) {
+ unset($form['user_cancel_method'][$element]['#description']);
+ }
- // Allow to send the account cancellation confirmation mail.
- $form['user_cancel_confirm'] = array(
- '#type' => 'checkbox',
- '#title' => t('Require e-mail confirmation to cancel account.'),
- '#default_value' => FALSE,
- '#description' => t('When enabled, the user must confirm the account cancellation via e-mail.'),
- );
- // Also allow to send account canceled notification mail, if enabled.
- $form['user_cancel_notify'] = array(
- '#type' => 'checkbox',
- '#title' => t('Notify user when account is canceled.'),
- '#default_value' => FALSE,
- '#access' => variable_get('user_mail_status_canceled_notify', FALSE),
- '#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'),
- );
+ // Allow to send the account cancellation confirmation mail.
+ $form['user_cancel_confirm'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Require e-mail confirmation to cancel account.'),
+ '#default_value' => FALSE,
+ '#description' => t('When enabled, the user must confirm the account cancellation via e-mail.'),
+ );
+ // Also allow to send account canceled notification mail, if enabled.
+ $form['user_cancel_notify'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Notify user when account is canceled.'),
+ '#default_value' => FALSE,
+ '#access' => variable_get('user_mail_status_canceled_notify', FALSE),
+ '#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'),
+ );
- return confirm_form($form,
- t('Are you sure you want to cancel these user accounts?'),
- 'admin/user/user', t('This action cannot be undone.'),
- t('Cancel accounts'), t('Cancel'));
+ return confirm_form($form,
+ t('Are you sure you want to cancel these user accounts?'),
+ 'admin/user/user', t('This action cannot be undone.'),
+ t('Cancel accounts'), t('Cancel'));
+ }
+ else {
+ $form = '';
+ return confirm_form($form,
+ t('No valid user accounts to cancel'),
+ 'admin/user/user',
+ t('You have not selected any valid user accounts to cancel. Go back and try again.'),
+ t('Cancel'),
+ NULL,
+ t('Cancel')
+ );
+ }
}
/**
@@ -2316,6 +2337,10 @@ function user_multiple_cancel_confirm_su
if ($form_state['values']['confirm']) {
foreach ($form_state['values']['accounts'] as $uid => $value) {
+ // Prevent uid 1 from being deleted.
+ if ($uid <= 1) {
+ continue;
+ }
// Prevent user administrators from deleting themselves without confirmation.
if ($uid == $user->uid) {
$admin_form_state = $form_state;
Index: modules/user/user.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.pages.inc,v
retrieving revision 1.45
diff -u -p -r1.45 user.pages.inc
--- modules/user/user.pages.inc 1 Jul 2009 12:47:30 -0000 1.45
+++ modules/user/user.pages.inc 7 Jul 2009 05:54:12 -0000
@@ -257,7 +257,7 @@ function user_profile_form($form_state,
$form['_category'] = array('#type' => 'value', '#value' => $category);
$form['_account'] = array('#type' => 'value', '#value' => $account);
$form['submit'] = array('#type' => 'submit', '#value' => t('Save'), '#weight' => 30);
- if (($account->uid == $user->uid && user_access('cancel account')) || user_access('administer users')) {
+ if ((($account->uid == $user->uid && user_access('cancel account')) || user_access('administer users')) && $account->uid > 1) {
$form['cancel'] = array(
'#type' => 'submit',
'#value' => t('Cancel account'),
Index: modules/user/user.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.test,v
retrieving revision 1.44
diff -u -p -r1.44 user.test
--- modules/user/user.test 1 Jul 2009 12:06:22 -0000 1.44
+++ modules/user/user.test 7 Jul 2009 05:54:12 -0000
@@ -162,7 +162,7 @@ class UserValidationTestCase extends Dru
class UserCancelTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
- 'name' => t('Cancel account'),
+ 'name' => t('Cancel an account'),
'description' => t('Ensure that account cancellation methods work as expected.'),
'group' => t('User'),
);
@@ -185,12 +185,12 @@ class UserCancelTestCase extends DrupalW
// Attempt to cancel account.
$this->drupalGet('user/' . $account->uid . '/edit');
- $this->assertNoRaw(t('Cancel account'), t('No cancel account button displayed.'));
+ $this->assertNoRaw(t('Cancel account'), t('Cancel account button is hidden if user does not have sufficient permission.'));
// Attempt bogus account cancellation request confirmation.
$timestamp = $account->login;
$this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
- $this->assertResponse(403, t('Bogus cancelling request rejected.'));
+ $this->assertResponse(403, t('Bogus account cancellation request was rejected.'));
$account = user_load($account->uid);
$this->assertTrue($account->status == 1, t('User account was not canceled.'));
@@ -241,6 +241,24 @@ class UserCancelTestCase extends DrupalW
}
/**
+ * Test for protection of user account #1 while logged as uid1.
+ * This should never be possible, for obvious reasons.
+ */
+ function testUserCancelUser1() {
+ variable_set('user_cancel_method', 'user_cancel_uid1_prevent');
+ // Fetch the uid1 account and and log them in.
+ $user1 = $this->drupalCreateUser();
+ $this->drupalLogin($user1);
+ $user1 = user_load(1, TRUE);
+ // Make sure the Cancel Account button does not show up on user/1/edit form.
+ $this->drupalGet('user/' . $user1->uid . '/edit');
+ $this->assertNoRaw(t('Cancel account'), t('Cancel account button is always hidden for user #1.'));
+ // Make sure the Edit checkbox does not show up on the admin/user page.
+ $this->drupalGet('admin/user/user');
+ $this->assertNoFieldByID('edit-accounts-1', 'unchecked', t('The Update checkbox for uid1 on the admin/user page does not appear.'));
+ }
+
+ /**
* Disable account and keep all content.
*/
function testUserBlock() {
@@ -450,7 +468,7 @@ class UserCancelTestCase extends DrupalW
}
/**
- * Create an administrative user and mass-delete other users.
+ * Create an administrative user and try to bulk-delete other users.
*/
function testMassUserCancelByAdmin() {
variable_set('user_cancel_method', 'user_cancel_reassign');
@@ -461,25 +479,24 @@ class UserCancelTestCase extends DrupalW
$admin_user = $this->drupalCreateUser(array('administer users'));
$this->drupalLogin($admin_user);
- // Create some users.
+ // Create three regular users.
$users = array();
for ($i = 0; $i < 3; $i++) {
$account = $this->drupalCreateUser(array());
$users[$account->uid] = $account;
}
-
- // Cancel user accounts, including own one.
+ // Attempt to cancel newly created user accounts.
$edit = array();
$edit['operation'] = 'cancel';
foreach ($users as $uid => $account) {
- $edit['accounts[' . $uid . ']'] = TRUE;
+ if ($uid > 1) {
+ $edit['accounts[' . $uid . ']'] = TRUE;
+ }
}
- $edit['accounts[' . $admin_user->uid . ']'] = TRUE;
$this->drupalPost('admin/user/user', $edit, t('Update'));
$this->assertText(t('Are you sure you want to cancel these user accounts?'), t('Confirmation form to cancel accounts displayed.'));
$this->assertText(t('When cancelling these accounts'), t('Allows to select account cancellation method.'));
$this->assertText(t('Require e-mail confirmation to cancel account.'), t('Allows to send confirmation mail.'));
- $this->assertText(t('Notify user when account is canceled.'), t('Allows to send notification mail.'));
// Confirm deletion.
$this->drupalPost(NULL, NULL, t('Cancel accounts'));
@@ -489,11 +506,13 @@ class UserCancelTestCase extends DrupalW
$status = $status && !user_load($account->uid, TRUE);
}
$this->assertTrue($status, t('Users deleted and not found in the database.'));
+ // $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), t('Account cancellation request mailed message displayed.'));
- // Ensure that admin account was not cancelled.
- $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), t('Account cancellation request mailed message displayed.'));
+ // Ensure that neither the administrative account nor uid1 was cancelled.
$admin_user = user_load($admin_user->uid);
- $this->assertTrue($admin_user->status == 1, t('Administrative user is found in the database and enabled.'));
+ $this->assertTrue($admin_user->status == 1, t('The administrative user still exists and is enabled.'));
+ $uid1 = user_load(1);
+ $this->assertTrue($uid1->status == 1, t('User #1 still exists and is enabled.'));
}
}