Commit 556af855 authored by Cecilia Vela Gurovic's avatar Cecilia Vela Gurovic Committed by Gerrit Code Review

Merge "Bug 1734178: allow user to delete own account"

parents c6dea210 9837f182
<?php
/**
*
* @package mahara
* @subpackage core
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('MENUITEM', 'settings/preferences');
require(dirname(dirname(__FILE__)) . '/init.php');
define('TITLE', get_string('deleteaccount', 'account', display_name($USER, null, false, false, true)));
if (!$USER->can_delete_self()) {
throw new AccessDeniedException(get_string('accessdenied', 'error'));
}
$cancelrequestform = pieform(array(
'name' => 'cancelrequest',
'plugintype' => 'core',
'pluginname' => 'account',
'elements' => array(
'user' => array(
'type' => 'hidden',
'value' => $USER->id,
),
'submit' => array(
'type' => 'submitcancel',
'class' => 'btn-default',
'value' => array(get_string('yes'), get_string('no')),
'goto' => get_config('wwwroot') . "account/index.php",
),
),
));
function cancelrequest_submit(Pieform $form, $values) {
global $SESSION;
if ($request = get_record('usr_pendingdeletion', 'usr', $values['user'])) {
delete_records('usr_pendingdeletion', 'id', $request->id);
$userid = $values['user'];
$user = new User;
$user->find_by_id($userid);
$admins = $user->get_approval_admins();
$user->notify_admins_pending_deletion($admins, '', 2);
$SESSION->add_ok_msg(get_string('deleterequestcanceled', 'account'));
}
redirect('/account/index.php');
}
$smarty = smarty();
$smarty->assign('cancelrequestform', $cancelrequestform);
$smarty->assign('userdisplayname', display_name($USER));
$smarty->display('account/cancelrequest.tpl');
......@@ -13,34 +13,77 @@ define('INTERNAL', 1);
define('MENUITEM', 'settings/preferences');
require(dirname(dirname(__FILE__)) . '/init.php');
define('TITLE', get_string('deleteaccount', 'account'));
define('TITLE', get_string('deleteaccount', 'account', display_name($USER, null, false, false, true)));
if (!$USER->can_delete_self()) {
throw new AccessDeniedException(get_string('accessdenied', 'error'));
}
$deleteform = pieform(array(
$deleteform = array(
'name' => 'account_delete',
'plugintype' => 'core',
'pluginname' => 'account',
'elements' => array(
);
$userid = $USER->get('id');
$user = new User;
$user->find_by_id($userid);
$requiresapproval = $user->requires_delete_approval();
if ($requiresapproval) {
$elements = array(
'reason' => array(
'type' => 'textarea',
'title' => get_string('reason'),
'cols' => 50,
'rows' => 4,
'rules' => array('required' => true),
),
'submit' => array(
'class' => 'btn-default',
'type' => 'submit',
'value' => get_string('deleteaccount', 'mahara', display_username($USER), full_name($USER)),
'type' => 'submitcancel',
'value' => array(get_string('senddeletenotification', 'mahara'), get_string('back')),
'goto' => get_config('wwwroot'). 'account/index.php',
),
),
));
);
}
else {
$elements = array(
'submit' => array(
'class' => 'btn-default',
'type' => 'submitcancel',
'value' => array(get_string('deleteaccount1', 'mahara'), get_string('back')),
'goto' => get_config('wwwroot'). 'account/index.php',
),
);
}
$deleteform['elements'] = $elements;
$deleteform = pieform($deleteform);
function account_delete_submit(Pieform $form, $values) {
global $SESSION, $USER;
global $SESSION, $USER, $user;
$userid = $USER->get('id');
$USER->logout();
delete_user($userid);
$SESSION->add_ok_msg(get_string('accountdeleted', 'account'));
redirect('/index.php');
// check if user needs approval to delete its account
if (!$user->requires_delete_approval()) {
$USER->logout();
delete_user($userid);
$SESSION->add_ok_msg(get_string('accountdeleted', 'account'));
}
else {
$admins = $user->get_approval_admins();
set_account_pending_deletion($userid, strip_tags(clean_html($values['reason'])));
$user->notify_admins_pending_deletion($admins, $values['reason']);
$SESSION->add_ok_msg(get_string('pendingdeletionemailsent', 'account'));
}
redirect('/account/index.php');
}
$smarty = smarty();
$smarty->assign('requiresapproval', $requiresapproval);
$smarty->assign('delete_form', $deleteform);
$smarty->assign('fullname', full_name($USER));
$smarty->assign('displayusername', display_username($USER));
$smarty->display('account/delete.tpl');
......@@ -116,6 +116,7 @@ if ($blogcount != 1 && $prefs->multipleblogs == 1) {
$elements['multipleblogs']['readonly'] = true;
}
$elements['submit'] = array(
'type' => 'submit',
'class' => 'btn-primary',
......@@ -281,8 +282,6 @@ function accountprefs_submit(Pieform $form, $values) {
$form->json_reply(PIEFORM_OK, $returndata);
}
$prefsform = pieform($prefsform);
$ijs = <<< EOF
......@@ -303,8 +302,13 @@ var clearPasswords = (function($) {
}
}(jQuery))
EOF;
$request = get_record('usr_pendingdeletion', 'usr', $USER->id);
$smarty = smarty();
$smarty->assign('form', $prefsform);
$smarty->assign('candeleteself', $USER->can_delete_self());
$smarty->assign('deletionsent', !empty($request));
$smarty->assign('requestdate', !empty($request) ? format_date(strtotime($request->ctime)) : '');
$smarty->assign('INLINEJAVASCRIPT', $ijs);
$smarty->display('account/index.tpl');
<?php
/**
*
* @package mahara
* @subpackage core
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('MENUITEM', 'settings/preferences');
require(dirname(dirname(__FILE__)) . '/init.php');
define('TITLE', get_string('deleteaccount', 'account', display_name($USER, null, false, false, true)));
if (!$USER->can_delete_self()) {
throw new AccessDeniedException(get_string('accessdenied', 'error'));
}
$deleteform = pieform(array(
'name' => 'account_resend',
'plugintype' => 'core',
'pluginname' => 'account',
'elements' => array(
'message' => array(
'type' => 'textarea',
'title' => get_string('message'),
'cols' => 50,
'rows' => 4,
'rules' => array('required' => true),
),
'submit' => array(
'class' => 'btn-default',
'type' => 'submit',
'value' => get_string('resenddeletionnotification', 'account'),
),
),
));
function account_resend_submit(Pieform $form, $values) {
global $SESSION, $USER;
$userid = $USER->get('id');
$user = new User;
$user->find_by_id($userid);
$admins = $user->get_approval_admins();
$user->notify_admins_pending_deletion($admins, strip_tags(clean_html($values['message'])), 1);
redirect('/account/index.php');
}
$smarty = smarty();
$smarty->assign('delete_form', $deleteform);
$smarty->display('account/resendnotification.tpl');
......@@ -326,6 +326,13 @@ $siteoptionform = array(
'help' => true,
'disabled' => in_array('institutionautosuspend', $OVERRIDDEN),
),
'defaultreviewselfdeletion' => array(
'type' => 'switchbox',
'title' => get_string('defaultreviewselfdeletion', 'admin'),
'description' => get_string('defaultreviewselfdeletiondescription', 'admin'),
'defaultvalue' => get_config('defaultreviewselfdeletion'),
'disabled' => in_array('defaultreviewselfdeletion', $OVERRIDDEN),
),
),
),
'accountsettings' => array(
......@@ -816,6 +823,7 @@ function siteoptions_submit(Pieform $form, $values) {
'staffreports', 'staffstats', 'userscandisabledevicedetection', 'watchlistnotification_delay',
'masqueradingreasonrequired', 'masqueradingnotified', 'searchuserspublic',
'eventloglevel', 'eventlogexpiry', 'eventlogenhancedsearch', 'sitefilesaccess', 'exporttoqueue', 'defaultmultipleblogs',
'defaultreviewselfdeletion'
);
if (get_config('dropdownmenuenabled')) {
$fields = array_merge($fields, array('dropdownmenu'));
......
<?php
/**
*
* @package mahara
* @subpackage core
* @author Stacey Walker
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('INSTITUTIONALADMIN', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
define('SECTION_PLUGINTYPE', 'core');
define('SECTION_PLUGINNAME', 'admin');
define('SECTION_PAGE', 'actiondeletion');
require_once('institution.php');
$id = param_integer('d');
$action = param_alpha('action');
if (!is_logged_in()) {
throw new AccessDeniedException();
}
if (!$deletion = get_record_select('usr_pendingdeletion', '"id" = ?', array($id))) {
die_info(get_string('userdeletionnosuchid', 'auth.internal'));
}
$usertodelete = new User();
$usertodelete->find_by_id($deletion->usr);
if ($action == 'approve') {
$message = get_string('approveuserdeletionmessage', 'admin', $usertodelete->username);
$submitbtn = get_string('approve', 'admin');
define('TITLE', get_string('approveuserdeletionfor', 'admin',
$usertodelete->firstname, $usertodelete->lastname, $usertodelete->email));
}
else {
$message = get_string('denyuserdeletionmessage', 'admin');
$submitbtn = get_string('deny', 'admin');
define('TITLE', get_string('denyuserdeletionfor', 'admin',
$usertodelete->firstname, $usertodelete->lastname));
$elements['message'] = array(
'type' => 'textarea',
'title' => get_string('deletiondeniedreason', 'admin'),
'description' => get_string('deletiondeniedreasondesc', 'admin'),
'cols' => 50,
'rows' => 10,
);
}
foreach ((array)$deletion as $key => $value) {
$elements[$key] = array(
'type' => 'hidden',
'value' => $value,
);
}
$elements['submit'] = array(
'type' => 'submitcancel',
'value' => array($submitbtn, get_string('cancel')),
'class' => 'btn-primary',
'goto' => get_config('wwwroot') . 'admin/users/pendingdeletions.php'
);
$form = pieform(array(
'name' => $action.'deletion',
'autofocus' => false,
'method' => 'post',
'elements' => $elements,
));
$smarty = smarty();
$smarty->assign('message', $message);
$smarty->assign('form', $form);
$smarty->display('admin/users/actiondeletion.tpl');
function denydeletion_submit(Pieform $form, $values) {
global $USER, $SESSION, $deletion, $usertodelete;
if (isset($values['message']) && !empty($values['message'])) {
$message = get_string('userdeletiondeniedmessagereason', 'auth.internal',
$usertodelete->firstname, get_config('sitename'), $values['message'], display_name($USER));
}
else {
$message = get_string('userdeletiondeniedmessage', 'auth.internal',
$usertodelete->firstname, get_config('sitename'), display_name($USER));
}
try {
delete_records('usr_pendingdeletion', 'id', $values['id']);
email_user($usertodelete, $USER,
get_string('userdeletiondeniedemailsubject', 'auth.internal', get_config('sitename')),
$message
);
}
catch (EmailException $e) {
log_warn($e);
die_info(get_string('userdeletiondeniedunsuccessful', 'admin'));
}
catch (SQLException $e) {
log_warn($e);
die_info(get_string('userdeletiondeniedunsuccessful', 'admin'));
}
$SESSION->add_ok_msg(get_string('userdeletiondeniedsuccessful', 'admin'));
redirect('/admin/users/pendingdeletions.php');
}
function approvedeletion_submit(Pieform $form, $values) {
global $SESSION, $usertodelete, $USER;
// cant delete the last site admin
$admins = get_site_admins();
$lastadminid = 0;
if (count($admins)== 1) {
$lastadminid = $admins[0]->id;
}
$usercanbedeleted = $candeleteuser = false;
// Check if user can be deleted
if (isset($values['id']) && isset($values['usr'])
&& ($values['usr'] != 0)
&& ($values['usr'] != $USER->get('id'))
&& ($values['usr'] != $lastadminid)
&& ($usrdeletion = get_record('usr_pendingdeletion', 'id', $values['id']))
&& ($usrdeletion->usr == $values['usr'])) {
$usercanbedeleted = true;
}
if ($usercanbedeleted) {
// Now check if we are allowed to delete them
$userinstitutions = $usertodelete->get('institutions');
if (empty($userinstitutions) && $USER->get('admin')) {
// we are only in 'mahara' institution so can only be deleted by site admins
$candeleteuser = true;
}
else {
foreach ($userinstitutions as $i) {
if ($USER->can_edit_institution($i->institution)) {
// If $USER can edit any of the institutions that the $user belongs then they are allowed to delete the user
$candeleteuser = true;
break;
}
}
}
}
if ($usercanbedeleted && $candeleteuser) {
delete_records('usr_pendingdeletion', 'id', $values['id']);
//delete user account
delete_user($values['usr']);
// send the user the official account deletion email
email_user(
$usertodelete,
null,
get_string('userdeletionemailsubject', 'auth.internal', get_config('sitename')),
get_string(
'userdeletionemailmessagetext',
'auth.internal',
$usertodelete->firstname,
get_config('sitename'),
get_config('sitename')
),
get_string(
'userdeletionemailmessagehtml',
'auth.internal',
$usertodelete->firstname,
get_config('sitename'),
get_config('sitename')
)
);
$SESSION->add_ok_msg(get_string('deletionapprovedsuccessfully', 'admin'));
}
else {
$SESSION->add_error_msg(get_string('deletionapprovedfailed', 'admin'));
}
redirect('/admin/users/pendingdeletions.php');
}
......@@ -228,6 +228,7 @@ if ($institution || $add) {
$data->commentsortorder = get_config_institution($institution, 'commentsortorder');
$data->commentthreaded = get_config_institution($institution, 'commentthreaded');
$data->allowinstitutionsmartevidence = get_config_institution($institution, 'allowinstitutionsmartevidence');
$data->reviewselfdeletion = get_config_institution($institution, 'reviewselfdeletion');
$lockedprofilefields = (array) get_column('institution_locked_profile_field', 'profilefield', 'name', $institution);
// TODO: Find a better way to work around Smarty's minimal looping logic
......@@ -584,6 +585,13 @@ if ($institution || $add) {
'disabled' => is_plugin_active('framework', 'module') == false,
'help' => true,
);
$elements['reviewselfdeletion'] = array(
'type' => 'switchbox',
'title' => get_string('reviewselfdeletion', 'admin'),
'description' => get_string('reviewselfdeletiondescription','admin'),
'disabled' => get_config('defaultreviewselfdeletion') == true,
'defaultvalue' => get_config('defaultreviewselfdeletion') ? get_config('defaultreviewselfdeletion') : (isset($data->reviewselfdeletion) && $data->reviewselfdeletion),
);
$elements['lockedfields'] = array(
'type' => 'fieldset',
'class' => 'last with-formgroup',
......@@ -930,6 +938,12 @@ function institution_submit(Pieform $form, $values) {
$newinstitution->allowinstitutionpublicviews = (isset($values['allowinstitutionpublicviews']) && $values['allowinstitutionpublicviews']) ? 1 : 0;
$newinstitution->allowinstitutionsmartevidence = (isset($values['allowinstitutionsmartevidence']) && $values['allowinstitutionsmartevidence']) ? 1 : 0;
// do not set 'reviewselfdeletion' if it has never been changed at institution level
// and the value is the same as site setting 'defaultreviewselfdeletion'
if (get_config_institution($institution, 'reviewselfdeletion') != null || get_config('defaultreviewselfdeletion') != $values['reviewselfdeletion']) {
$newinstitution->reviewselfdeletion = $values['reviewselfdeletion'] ? 1 : 0;
}
// TODO: Move handling of authentication instances within the Institution class as well?
if (!empty($values['authplugin'])) {
$allinstances = array_merge($values['authplugin']['instancearray'], $values['authplugin']['deletearray']);
......
<?php
/**
*
* @package mahara
* @subpackage admin
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('INSTITUTIONALADMIN', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
define('TITLE', get_string('pendingdeletions', 'admin'));
define('SECTION_PLUGINTYPE', 'core');
define('SECTION_PLUGINNAME', 'admin');
define('SECTION_PAGE', 'pendingdeletions');
define('MENUITEM', 'manageinstitutions/pendingdeletions');
require_once('institution.php');
if (!is_logged_in()) {
throw new AccessDeniedException();
}
$institutionelement = get_institution_selector();
if (empty($institutionelement)) {
$smarty = smarty();
$smarty->display('admin/users/noinstitutions.tpl');
exit;
}
$institution = param_alphanum('institution', null);
if (!$institution || !$USER->can_edit_institution($institution)) {
$institution = empty($institutionelement['value']) ? $institutionelement['defaultvalue'] : $institutionelement['value'];
}
else if (!empty($institution)) {
$institutionelement['defaultvalue'] = $institution;
}
$institutionselector = pieform(array(
'name' => 'usertypeselect',
'class' => 'form-inline',
'elements' => array(
'institution' => $institutionelement,
)
));
if ($institution == 'mahara') {
$pending = get_records_sql_array('
SELECT d.*, u.id AS userid, u.username
FROM {usr_pendingdeletion} d
JOIN {usr} u ON d.usr = u.id
WHERE NOT EXISTS (SELECT * FROM {usr_institution} ui WHERE ui.usr = u.id)
ORDER BY d.ctime ASC'
);
}
else {
$instobj = new Institution($institution);
if ($instobj->requires_user_deletion_approval()) {
$pending = get_records_sql_array('
SELECT d.*, u.id AS userid, u.username
FROM {usr_pendingdeletion} d
JOIN {usr} u ON d.usr = u.id
JOIN {usr_institution} ui ON ui.usr = u.id
WHERE ui.institution = ?
ORDER BY d.ctime ASC',
array($institution)
);
}
}
if (!isset($pending) || !$pending) {
$pending = array();
}
function build_pending_html($data, $institution) {
foreach ($data as $d) {
$d->displayname = display_name($d->userid, null, true);
}
$smarty = smarty_core();
$smarty->assign('data', isset($data) ? $data : null);
$smarty->assign('institution', $institution);
$tablerows = $smarty->fetch('admin/users/pendingdeletionlist.tpl');
return $tablerows;
}
$data = build_pending_html($pending, $institution);
$wwwroot = get_config('wwwroot');
$js = <<< EOF
jQuery(function($) {
function reloadUsers() {
window.location.href = '{$wwwroot}admin/users/pendingdeletions.php?institution='+$('#usertypeselect_institution').val();
}
$('#usertypeselect_institution').on('change', reloadUsers);
});
EOF;
$smarty = smarty();
setpageicon($smarty, 'icon-university');
$smarty->assign('INLINEJAVASCRIPT', $js);
$smarty->assign('data', $data);
$smarty->assign('institutionselector', $institutionselector);
$smarty->display('admin/users/pendingdeletions.tpl');
......@@ -140,3 +140,44 @@ $string['pendingregistrationadminemailhtml'] = "<p>Hi %s,</p>
<pre>--
Regards,
The %s Team</pre>";
// pending user account deletion
$string['userdeletionnosuchid'] = 'Sorry, this deletion request does not exist. Perhaps it has already been evaluated?';
$string['userdeletiondeniedmessage'] = 'Hello %s,
We have received your request to delete your user account on %s and
decided not to delete your data.
If you think that this decision was incorrect, please get in touch with me
via email.
Regards
%s';
$string['userdeletiondeniedmessagereason'] = 'Hello %s,
We have received your request to delete your user account on %s and decided
not to delete your data for the following reason:
%s
If you think that this decision was incorrect, please get in touch with me
via email.
Regards
%s';
$string['userdeletiondeniedemailsubject'] = 'User account deletion attempt at %s denied.';
$string['userdeletionemailsubject'] = 'Your user account was deleted from %s';
$string['userdeletionemailmessagetext'] = 'Hello %s,
Your user account was deleted successfully from %s.