Merge pull request #2649 from drshawnkwang/drupal_feature-deleteuser-improve

Drupal: Improved delete user operations.
This commit is contained in:
tristanolive 2018-08-23 10:38:32 -04:00 committed by GitHub
commit 515620c9a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 354 additions and 96 deletions

View File

@ -361,6 +361,21 @@ echo \'<div class="item-count-wrapper"><div class="item-count">\' . $account->po
'css' => '',
'contexts' => array(),
'relationships' => array(),
'access' => array(
'plugins' => array(
0 => array(
'name' => 'php',
'settings' => array(
'description' => 'if user status then show profile',
'php' => '$account = $contexts[\'argument_uid_1\']->data;
return ($account->status);
',
),
'not' => FALSE,
),
),
'logic' => 'and',
),
);
$display = new panels_display;
$display->layout = 'one_sidebar_second';

View File

@ -274,6 +274,7 @@ function boincuser_init() {
if (module_exists('boincuser_delete')) {
$paths_to_ignore[] = 'user/' . $user->uid . '/delete';
$paths_to_ignore[] = 'user/' . $user->uid . '/deleteconfirm/*';
$paths_to_ignore[] = 'user/' . $user->uid . '/odeleteconfirm/*';
}
if (!_boincuser_ignore_paths($path, $paths_to_ignore)) {
drupal_goto('user/termsofuse');

View File

@ -16,9 +16,30 @@ function boincuser_delete_settings() {
$form = array();
$default = array(
'boincuser_delete_type' => variable_get('boincuser_delete_type', ''),
'boincuser_delete_redirect' => variable_get('boincuser_delete_redirect', '<front>'),
);
$form['options'] = array(
'#type' => 'fieldset',
'#title' => t('Options'),
);
$form['options']['help'] = array(
'#value' => t('When a user deletes their account, which option is shown to the user? A soft/obfusate delete, a hard/wipe delete, or let the user chose between the two.'),
'#weight' => 11,
);
$form['options']['boincuser_delete_type'] = array(
'#type' => 'radios',
'#title' => t('Type of delete'),
'#default_value' => $default['boincuser_delete_type'],
'#options' => array(
'soft_obfuscate' => t('A soft/obfuscate delete. User\'s account is disabled, but some data is deleted.'),
'hard_wipe' => t('A hard/wipe delete. User\'s account is deleted along with many data.'),
'user_decides' => t('User is presented with radio buttons where they choose between the two options above.'),
),
'#weight' => 21,
);
$form['redirect'] = array(
'#type' => 'fieldset',
'#title' => t('Redirect'),
@ -44,7 +65,7 @@ function boincuser_delete_admindelete(&$form_state, $uid) {
$form['#uid'] = $uid;
$form['account']['help'] = array(
'#value' => "<p>" . t("This form will delete this user <strong>without any email notification</strong> sent to the user. Be very careful in deleting users using this form. Once you enter your password, check the checkbox, and click submit, the user's account will be deleted. This will occur <strong>immediately</strong>. There is no 'undo'!") . "</p><p>" . t("You are deleting the following user:") . "</p>",
'#value' => "<p>" . t("This form will delete this user <strong>without any email notification</strong> sent to the user. Be very careful in deleting users using this form. Once you select the delete type, check the checkbox, enter your password, and click submit, the user's account will be deleted. This will occur <strong>immediately</strong>. There is no 'undo'!") . "</p><p>" . t("You are deleting the following user, link opens in new window:") . "</p>",
'#weight' => -1,
'#prefix' => "<div id='delete-instructions'>",
'#suffix' => "</div>",
@ -55,7 +76,7 @@ function boincuser_delete_admindelete(&$form_state, $uid) {
drupal_set_title($account->boincuser_name);
$form['account']['boincuser_name'] = array(
'#value' => t('<li>BOINC username (public displayname): ') . $account->boincuser_name,
'#value' => t('<li>BOINC username (public displayname): ') . l("{$account->boincuser_name}", "account/{$account->uid}", array('attributes' => array('target' => '_blank'))),
);
$form['account']['boincuser_id'] = array(
'#value' => t('<li>BOINC user ID: ') . $account->boincuser_id,
@ -67,6 +88,13 @@ function boincuser_delete_admindelete(&$form_state, $uid) {
'#value' => t('<li>Drupal user ID: ') . $account->uid,
);
$form['account']['user_delete_action'] = array(
'#type' => 'radios',
'#options' => array(
'soft_obfuscate' => bts('<b>Soft delete</b> the account. The account will be disabled, and all posts/comments will be attributed to the Anonymous User. The user profile will be deleted, the host information deleted, and the user will be removed from any team.', array(), NULL, 'boinc:delete-user-account'),
'hard_wipe' => bts('<b>Delete</b> the account. The account will be deleted, and all posts/comments will be attributed to the Anonymous User. The user profile will be deleted.', array(), NULL, 'boinc:delete-user-account'),),
);
$form['account']['surecheckbox'] = array(
'#type' => 'checkbox',
'#title' => t('I am <strong>sure</strong> I know what I am doing. I am <u><strong>deleting user</strong></u> %name.',
@ -116,6 +144,14 @@ function boincuser_delete_admindelete_validate($form, &$form_state) {
global $user;
$boinc_user = boincuser_load($user->uid, TRUE);
if ($form_state['values']['user_delete_action'] == '') {
form_set_error('user_delete_action', t('Please select an action to perform using the radio buttons.'));
}
if ( ($form_state['values']['user_delete_action'] != 'soft_obfuscate') and ($form_state['values']['user_delete_action'] != 'hard_wipe') ) {
form_set_error('user_delete_action', t('User Delete action not a predefined value, unknown error in radio buttons.'));
}
if (!($form_state['values']['surecheckbox'])) {
return form_set_error('surecheckbox', t('Please confirm you are sure you want to delete this account.'));
}
@ -129,12 +165,10 @@ function boincuser_delete_admindelete_validate($form, &$form_state) {
* Submit function for admin delete user.
*/
function boincuser_delete_admindelete_submit($form, &$form_state) {
require_boinc('user_util');
require_boinc('delete_account');
// This is the account to be deleted, and not the administrator's
// account.
$account = user_load(array('uid' => $form['#uid']));
$action = $form_state['values']['user_delete_action'];
drupal_set_message(t('WARNING: Account @displayname, Drupal UID=@uid has been deleted.',
array(
@ -142,18 +176,8 @@ function boincuser_delete_admindelete_submit($form, &$form_state) {
'@displayname' => $account->boincuser_name,
)), 'warning');
// watchdog message
watchdog('boincuser_delete', 'Deleting account drupal UID: %uid, BOINC id: %boincuser_id., BOINC displayname: %displayname',
array(
'%uid' => $form['#uid'],
'%boincuser_id' => $account->boincuser_id,
'%displayname' => $account->boincuser_name,
), WATCHDOG_NOTICE);
// Delete the user
$boinc_user = boincuser_load($account->uid, TRUE);
wipe_account($boinc_user);
user_delete(array(), $account->uid);
_boincuser_delete_deleteuser($account, $action);
drupal_goto('/admin/boinc/user_delete');
}

View File

@ -57,6 +57,16 @@ function boincuser_delete_menu() {
'type' => MENU_CALLBACK,
);
$items['user/%user/odeleteconfirm/%'] = array(
'title' => t('Final confirmation for account deletion'),
'description' => t('Final confirmation for account deletion'),
'page callback' => 'drupal_get_form',
'page arguments' => array('boincuser_delete_softdelconfirmation', 3),
'access callback' => 'boincuser_delete_access',
'access arguments' => array(1),
'type' => MENU_CALLBACK,
);
return $items;
}
@ -125,6 +135,24 @@ function boincuser_delete_form_alter(&$form, $form_state, $form_id) {
$disable_delete = TRUE;
}
// Configure radio options
$deleteoptions = array(
'boincuser_delete_softdelete' => bts('<b>Soft delete</b> the account. Afterwards your account will be disabled, and all posts/comments will be attributed to the Anonymous User. However, your user profile will be deleted, your host information deleted, and you will be removed from any team you are a member of.', array(), NULL, 'boinc:delete-user-account'),
'boincuser_delete_delete' => bts('<b>Delete</b> the account. Afterwards your account will be deleted, and all posts/comments will be attributed to the Anonymous User. Your user profile will be deleted.', array(), NULL, 'boinc:delete-user-account'),
);
$dtypes = variable_get('boincuser_delete_type', 'user_decides');
// unset the other option if dtype is set. i.e., if dtype is set
// to soft delete, unset the hard delete option.
switch ($dtypes) {
case 'soft_obfuscate':
unset($deleteoptions['boincuser_delete_delete']);
break;
case 'hard_wipe':
unset($deleteoptions['boincuser_delete_softdelete']);
break;
}
$question = 'Are you sure you want to delete the account <em>' . htmlspecialchars($form['_account']['#value']->boincuser_name) . '</em>?';
drupal_set_title($question);
@ -149,9 +177,7 @@ function boincuser_delete_form_alter(&$form, $form_state, $form_id) {
$form['main']['user_delete_action'] = array(
'#type' => 'radios',
'#options' => array(
'boincuser_delete_delete' => bts('<b>Delete</b> the account. Afterwards your account will be deleted, and all posts/comments will be attributed to the Anonymous User. Your user profile will be deleted.', array(), NULL, 'boinc:delete-user-account'),
),
'#options' => $deleteoptions,
'#weight' => 21,
);
if ($disable_delete) {
@ -267,43 +293,45 @@ function boincuser_delete_submit($form, &$form_state) {
global $base_url;
global $base_path;
module_load_include('inc', 'rules', 'modules/system.rules');
$mysubject = '';
$mymessage = '';
$site_name = variable_get('site_name', 'Drupal-BOINC');
$site_url = $base_url . $base_path . "user/login";
// Perform the requested operation
$op = $form_state['values']['user_delete_action'];
// create token with 1 day/24 hour expiration
$mytoken = create_token($account->boincuser_id, 'D', 24*60*60);
switch ($op) {
case 'boincuser_delete_softdelete':
$myurl = "${base_url}/user/{$account->uid}/odeleteconfirm/$mytoken";
break;
case 'boincuser_delete_delete':
// create token with 1 day/24 hour expiration
$mytoken = create_token($account->boincuser_id, 'D', 24*60*60);
$mysubject = "Instructions for account deletion at {$site_name}";
$mymessage = ''
. "{$account->boincuser_name},\n"
. "\n"
. "We have received a request to DELETE your user account at "
. "${site_name}. Below in this email is a one-time token you must "
. "use. Either click on the link or copy-and-paste the URL into your "
. "browser address bar. Then you will be required to enter your password "
. "again to confirm your identity.\n"
. "\n"
. "${base_url}/user/{$account->uid}/deleteconfirm/$mytoken\n"
. "\n"
. "This one-time token will expire in 24 hours. Afterwards you must "
. "re-request deletion of your account in order to generate a new token.\n"
. "\n"
. "If you did not initiate this request, please login to the "
. "${site_name} Web site (${site_url}) and "
. "then contact the administrators.\n"
. "\n"
. "Thanks, \n"
. "\n"
. "{$site_name} support team";
$myurl = "${base_url}/user/{$account->uid}/deleteconfirm/$mytoken";
break;
}
$mysubject = "Instructions for account deletion at {$site_name}";
$mymessage = ''
. "{$account->boincuser_name},\n"
. "\n"
. "We have received a request to DELETE your user account at "
. "${site_name}. Below in this email is a one-time token you must "
. "use. Either click on the link or copy-and-paste the URL into your "
. "browser address bar. Then you will be required to enter your password "
. "again to confirm your identity.\n"
. "\n"
. "${myurl}\n"
. "\n"
. "This one-time token will expire in 24 hours. Afterwards you must "
. "re-request deletion of your account in order to generate a new token.\n"
. "\n"
. "If you did not initiate this request, please login to the "
. "${site_name} Web site (${site_url}) and "
. "then contact the administrators.\n"
. "\n"
. "Thanks, \n"
. "\n"
. "{$site_name} support team";
// Create array for sending email to user to notify account is being
// disabled/deleted. Then send email.
$settings = array(
@ -356,6 +384,9 @@ function boincuser_delete_finalconfirmation(&$form_state, $token) {
// Attach account to this form.
$form['_account'] = array('#type' => 'value', '#value' => $account);
// This form is for hard/wipe delete
$form['_action'] = array('#type' => 'value', '#value' => 'hard_wipe');
// Instructions
$form['main']['instructions1'] = array(
'#value' => '<p>'.
@ -404,6 +435,88 @@ function boincuser_delete_finalconfirmation(&$form_state, $token) {
return $form;
}
/**
* Final confirmation form for the user to delete their account, using
* the soft/obfuscate method.
*/
function boincuser_delete_softdelconfirmation(&$form_state, $token) {
require_boinc('token');
global $user;
$form = array();
// check BOINC user exists
$account = user_load(array('uid' => $user->uid));
$uid = $user->uid;
$boincid = $account->boincuser_id;
// check $token is valid
if (!is_valid_token($boincid, $token, 'D')) {
drupal_set_message(bts('ERROR: You have supplied an incorrect (most likely expired) token. Please obtain a new token by !link your account be deleted.',
array(
'!link' => l(bts('re-requesting', array(), NULL, 'boinc:delete-user-account'), "/user/${uid}/delete"),
),
NULL, 'boinc:delete-user-account'), 'error');
drupal_goto();
}
// Attach account to this form.
$form['_account'] = array('#type' => 'value', '#value' => $account);
// This form is for hard/wipe delete
$form['_action'] = array('#type' => 'value', '#value' => 'soft_obfuscate');
// Instructions
$form['main']['instructions1'] = array(
'#value' => '<p>'.
bts('You are one-step away from deleting your account. Enter your password in the textbox below and click submit. This action is irreversable: once you delete your account, there is no way un-delete.', array(), NULL, 'boinc:delete-user-account').
'</p>',
);
$form['main']['instructions2'] = array(
'#value' => '<p>'.
bts('If you wish to cancel, click cancel and you will be taken to your account dashboard.', array(), NULL, 'boinc:delete-user-account').
'</p>',
);
// Password field
$form['main']['current_pass'] = array(
'#type' => 'password',
'#title' => bts('Enter your password before clicking Submit', array(), NULL, 'boinc:delete-user-account'),
'#size' => 17,
'#attributes' => array(
'autocomplete' => 'off',
),
'#weight' => 25,
);
// Form control
$form['form control tabs prefix'] = array(
'#value' => '<ul class="form-control tab-list">',
'#weight' => 1001,
);
$form['submit'] = array(
'#prefix' => '<li class="first tab">',
'#type' => 'submit',
'#value' => bts('Submit', array(), NULL, 'boinc:form-submit'),
'#suffix' => '</li>',
'#weight' => 1002,
);
$form['form control tabs'] = array(
'#value' => '<li class="tab">' . l(bts('Cancel', array(), NULL, 'boinc:form-cancel'), "account/") . '</li>',
'#weight' => 1003,
);
$form['form control tabs suffix'] = array(
'#value' => '</ul>',
'#weight' => 1004,
);
//set validation and submit to the functions below
$form['#validate'][] = 'boincuser_delete_finalconfirmation_validate';
$form['#submit'][] = 'boincuser_delete_finalconfirmation_submit';
return $form;
}
/**
* Validation for final confirmation
*/
@ -420,27 +533,12 @@ function boincuser_delete_finalconfirmation_validate($form, &$form_state) {
* Submit for final confirmation
*/
function boincuser_delete_finalconfirmation_submit($form, &$form_state) {
require_boinc('user_util');
require_boinc('delete_account');
global $user;
// Delete the user
$account = $form_state['values']['_account'];
$boinc_user = BoincUser::lookup_id($account->boincuser_id);
// watchdog message
watchdog('boincuser_delete', 'Deleting account drupal UID: %uid, BOINC id: %boincuser_id., BOINC displayname: %displayname',
array(
'%uid' => $account->uid,
'%boincuser_id' => $account->boincuser_id,
'%displayname' => $account->boincuser_name,
), WATCHDOG_NOTICE);
// delete the account - This will delete the boinc user from the
// boinc project database, and then delete the Drupal user using the
// hook_user() functions.
wipe_account($boinc_user);
user_delete(array(), $account->uid);
$action = $form_state['values']['_action'];
_boincuser_delete_deleteuser($account, $action);
// Destroy the current session:
session_destroy();

View File

@ -31,4 +31,122 @@ function _boincuser_delete_validatepasswd($boinc_user, $current_pass) {
}
return true;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Custom delete functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Delete the user function.
*/
function _boincuser_delete_deleteuser($account, $action=NULL) {
require_boinc('user_util');
require_boinc('delete_account');
$boinc_user = BoincUser::lookup_id($account->boincuser_id);
// watchdog message
watchdog('boincuser_delete', 'Deleting account drupal UID: %uid, BOINC id: %boincuser_id., BOINC displayname: %displayname',
array(
'%uid' => $account->uid,
'%boincuser_id' => $account->boincuser_id,
'%displayname' => $account->boincuser_name,
), WATCHDOG_NOTICE);
// delete the account - This will delete the boinc user from the
// boinc project database, and then delete the Drupal user using the
// hook_user() functions.
switch ($action) {
case 'soft_obfuscate':
obfuscate_account($boinc_user);
_boincuser_delete_comment_reassign($account);
_boincuser_delete_node_reassign($account);
_boincuser_delete_privatemsg_delete($account);
_boincuser_delete_friends($account);
// delete the user's profile
$profile = content_profile_load('profile', $account->uid);
node_delete($profile->nid);
// Drupal account -
// * 'block'/disable the account
// * set name, mail, pass, and init to deleted
// * erase signature
$myarray = array(
'status' => 0,
'name' => 'deleted_' . time() . '_' . random_string(),
'mail' => 'deleted_' . time() . '_' . random_string(),
'pass' => 'deleted_' . time() . '_' . random_string(),
'signature' => '',
'init' => 'deleted_' . time() . '_' . random_string(),
);
user_save($account, $myarray);
break;
case 'hard_wipe':
wipe_account($boinc_user);
user_delete(array(), $account->uid);
break;
default:
watchdog('boincuser_delete', 'Delete action is %action, which is not \'soft_obfuscate\' or \'hard_wipe\'.', array(
'%action' => $action,
), WATCHDOG_ERROR);
}
}
/**
* Assigns nodes to anonymous user.
*
* Copied from node.module, node_user()
*/
function _boincuser_delete_node_reassign($account) {
db_query('UPDATE {node} SET uid = 0 WHERE uid = %d', $account->uid);
db_query('UPDATE {node_revisions} SET uid = 0 WHERE uid = %d', $account->uid);
}
/**
* Assigns comments to anonymous user.
*
* Copied from comment.module, comment_user()
*/
function _boincuser_delete_comment_reassign($account) {
// bug in comment module, remove user name from comments.
db_query("UPDATE {comments} SET comments.name='' WHERE uid =%d", $account->uid);
db_query('UPDATE {comments} SET uid = 0 WHERE uid = %d', $account->uid);
db_query('UPDATE {node_comment_statistics} SET last_comment_uid = 0 WHERE last_comment_uid = %d', $account->uid);
}
/**
* Deletes private messages
*
* Copied from privatemsg module, case 'delete' in privatemsg_user().
*/
function _boincuser_delete_privatemsg_delete($account) {
// Load all mids of the messages the user wrote.
$result = db_query("SELECT mid FROM {pm_message} WHERE author = %d", $account->uid);
$mids = array();
while ($row = db_fetch_array($result)) {
$mids[] = $row['mid'];
}
// Delete messages the user wrote.
db_query('DELETE FROM {pm_message} WHERE author = %d', $account->uid);
if (!empty($mids)) {
// Delete recipient entries in {pm_index} of the messages the user wrote.
db_query('DELETE FROM {pm_index} WHERE mid IN (' . db_placeholders($mids) . ')', $mids);
}
// Delete recipient entries of that user.
db_query('DELETE FROM {pm_index} WHERE uid = %d', $account->uid);
}
/**
* Deletes the friend connections for this user
*
* Copied from flag_friend, flag_friend_user()
*/
function _boincuser_delete_friends($account) {
// remove any friend relationships if an account is removed
db_query("DELETE FROM {flag_friend} WHERE uid = %d OR friend_uid = %d", $account->uid, $account->uid);
}

View File

@ -163,39 +163,41 @@ if ($user->uid AND ($user->uid != $account->uid)) {
<span class="label"></span>
<span class="value"><?php print $name; ?></span>
</div>
<div class="join-date">
<span class="label"><?php print bts('Member since', array(), NULL, 'boinc:user-info'); ?>:</span>
<span class="value"><?php print $join_date; ?></span>
</div>
<div class="country">
<span class="label"><?php print bts('Country', array(), NULL, 'boinc:country-of-origin'); ?>:</span>
<span class="value"><?php print $country; ?></span>
</div>
<div class="boincid">
<span class="value"><?php print bts('BOINC ID', array(), NULL, 'boinc:boincid'); ?>:</span>
<span class="value"><?php print $boincid; ?></span>
</div>
<?php if ($website AND ($profile_is_approved OR $user_is_moderator OR $is_own_profile)): ?>
<div class="website">
<span class="label"><?php print bts('Website', array(), NULL, 'boinc:website-of-user-of-team'); ?>:</span>
<span class="value"><?php print l($website, (strpos($website, 'http') === false) ? "http://{$website}" : $website); ?></span>
<?php if ($account->status==1): ?>
<div class="join-date">
<span class="label"><?php print bts('Member since', array(), NULL, 'boinc:user-info'); ?>:</span>
<span class="value"><?php print $join_date; ?></span>
</div>
<?php endif; ?>
<?php if ($user->uid AND ($user->uid != $account->uid)): ?>
<ul class="tab-list">
<?php foreach ($user_links as $key => $link): ?>
<li class="primary <?php print ($key == 0) ? 'first ' : ''; ?>tab<?php print ($key == count($user_links)-1) ? ' last' : ''; ?>">
<?php print l($link['title'], $link['href'], array('query' => drupal_get_destination())); ?>
</li>
<?php endforeach; ?>
</ul>
<ul class="tab-list">
<?php foreach ($user_links2l as $key => $link): ?>
<li class="primary <?php print ($key == 0) ? 'first ' : ''; ?>tab<?php print ($key == count($user_links2l)-1) ? ' last' : ''; ?>">
<?php print l($link['title'], $link['href'], array('query' => drupal_get_destination())); ?>
</li>
<?php endforeach; ?>
</ul>
<div class="country">
<span class="label"><?php print bts('Country', array(), NULL, 'boinc:country-of-origin'); ?>:</span>
<span class="value"><?php print $country; ?></span>
</div>
<div class="boincid">
<span class="value"><?php print bts('BOINC ID', array(), NULL, 'boinc:boincid'); ?>:</span>
<span class="value"><?php print $boincid; ?></span>
</div>
<?php if ($website AND ($profile_is_approved OR $user_is_moderator OR $is_own_profile)): ?>
<div class="website">
<span class="label"><?php print bts('Website', array(), NULL, 'boinc:website-of-user-of-team'); ?>:</span>
<span class="value"><?php print l($website, (strpos($website, 'http') === false) ? "http://{$website}" : $website); ?></span>
</div>
<?php endif; ?>
<?php if ($user->uid AND ($user->uid != $account->uid)): ?>
<ul class="tab-list">
<?php foreach ($user_links as $key => $link): ?>
<li class="primary <?php print ($key == 0) ? 'first ' : ''; ?>tab<?php print ($key == count($user_links)-1) ? ' last' : ''; ?>">
<?php print l($link['title'], $link['href'], array('query' => drupal_get_destination())); ?>
</li>
<?php endforeach; ?>
</ul>
<ul class="tab-list">
<?php foreach ($user_links2l as $key => $link): ?>
<li class="primary <?php print ($key == 0) ? 'first ' : ''; ?>tab<?php print ($key == count($user_links2l)-1) ? ' last' : ''; ?>">
<?php print l($link['title'], $link['href'], array('query' => drupal_get_destination())); ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<?php endif; ?>
<div class="clearfix"></div>
</div>