From 4ad72c284d1d864060c4399150cf973e5f2abc4f Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Tue, 3 Jan 2012 13:18:06 +0100 Subject: [PATCH] MDL-30548 support user suspended flag in admin UI This patch includes: * user management suspend UI tweaks and other coding style improvements * suspended info in user profiles * suspend option in advanced edit form * suspended user filtering * hidden user fields option for suspended field Thanks Sam Hemelryk for valuable feedback. --- admin/settings/users.php | 4 +- admin/user.php | 150 ++++++++++++++++++++++++------------- lang/en/admin.php | 2 + lang/en/auth.php | 2 + lib/datalib.php | 2 +- theme/base/style/core.css | 4 + user/editadvanced.php | 6 ++ user/editadvanced_form.php | 19 +++++ user/filters/lib.php | 3 +- user/profile.php | 6 ++ user/view.php | 6 ++ 11 files changed, 150 insertions(+), 54 deletions(-) diff --git a/admin/settings/users.php b/admin/settings/users.php index 256da1742b5..717a092445b 100644 --- a/admin/settings/users.php +++ b/admin/settings/users.php @@ -127,7 +127,9 @@ if ($hassiteconfig 'firstaccess' => get_string('firstaccess'), 'lastaccess' => get_string('lastaccess'), 'mycourses' => get_string('mycourses'), - 'groups' => get_string('groups')))); + 'groups' => get_string('groups'), + 'suspended' => get_string('suspended', 'auth'), + ))); // Select fields to display as part of user identity (only to those // with moodle/site:viewuseridentity). diff --git a/admin/user.php b/admin/user.php index 9453dbf7850..1ccb69fe15d 100644 --- a/admin/user.php +++ b/admin/user.php @@ -14,7 +14,8 @@ $ru = optional_param('ru', '2', PARAM_INT); // show remote users $lu = optional_param('lu', '2', PARAM_INT); // show local users $acl = optional_param('acl', '0', PARAM_INT); // id of user to tweak mnet ACL (requires $access) - + $suspend = optional_param('suspend', 0, PARAM_INT); + $unsuspend = optional_param('unsuspend', 0, PARAM_INT); admin_externalpage_setup('editusers'); @@ -29,6 +30,9 @@ $strdelete = get_string('delete'); $strdeletecheck = get_string('deletecheck'); $strshowallusers = get_string('showallusers'); + $strsuspend = get_string('suspenduser', 'admin'); + $strunsuspend = get_string('unsuspenduser', 'admin'); + $strconfirm = get_string('confirm'); if (empty($CFG->loginhttps)) { $securewwwroot = $CFG->wwwroot; @@ -36,10 +40,11 @@ $securewwwroot = str_replace('http:','https:',$CFG->wwwroot); } - $returnurl = "$CFG->wwwroot/$CFG->admin/user.php"; + $returnurl = new moodle_url('/admin/user.php', array('sort' => $sort, 'dir' => $dir, 'perpage' => $perpage, 'page'=>$page)); if ($confirmuser and confirm_sesskey()) { - if (!$user = $DB->get_record('user', array('id'=>$confirmuser))) { + require_capability('moodle/user:update', $sitecontext); + if (!$user = $DB->get_record('user', array('id'=>$confirmuser, 'mnethostid'=>$CFG->mnet_localhost_id))) { print_error('nousers'); } @@ -55,10 +60,9 @@ } } else if ($delete and confirm_sesskey()) { // Delete a selected user, after confirmation - require_capability('moodle/user:delete', $sitecontext); - $user = $DB->get_record('user', array('id'=>$delete), '*', MUST_EXIST); + $user = $DB->get_record('user', array('id'=>$delete, 'mnethostid'=>$CFG->mnet_localhost_id), '*', MUST_EXIST); if (is_siteadmin($user->id)) { print_error('useradminodelete', 'error'); @@ -69,7 +73,7 @@ $fullname = fullname($user, true); echo $OUTPUT->heading(get_string('deleteuser', 'admin')); $optionsyes = array('delete'=>$delete, 'confirm'=>md5($delete), 'sesskey'=>sesskey()); - echo $OUTPUT->confirm(get_string('deletecheckfull', '', "'$fullname'"), new moodle_url('user.php', $optionsyes), 'user.php'); + echo $OUTPUT->confirm(get_string('deletecheckfull', '', "'$fullname'"), new moodle_url($returnurl, $optionsyes), $returnurl); echo $OUTPUT->footer(); die; } else if (data_submitted() and !$user->deleted) { @@ -83,8 +87,7 @@ } } } else if ($acl and confirm_sesskey()) { - if (!has_capability('moodle/user:delete', $sitecontext)) { - // TODO: this should be under a separate capability + if (!has_capability('moodle/user:update', $sitecontext)) { print_error('nopermissions', 'error', '', 'modify the NMET access control list'); } if (!$user = $DB->get_record('user', array('id'=>$acl))) { @@ -110,6 +113,36 @@ } $mnethosts = $DB->get_records('mnet_host', null, 'id', 'id,wwwroot,name'); redirect($returnurl); + + } else if ($suspend and confirm_sesskey()) { + require_capability('moodle/user:update', $sitecontext); + + if ($user = $DB->get_record('user', array('id'=>$suspend, 'mnethostid'=>$CFG->mnet_localhost_id, 'deleted'=>0))) { + if (!is_siteadmin($user) and $USER->id != $user->id and $user->suspended != 1) { + $user->suspended = 1; + $user->timemodified = time(); + $DB->set_field('user', 'suspended', $user->suspended, array('id'=>$user->id)); + $DB->set_field('user', 'timemodified', $user->timemodified, array('id'=>$user->id)); + // force logout + session_kill_user($user->id); + events_trigger('user_updated', $user); + } + } + redirect($returnurl); + + } else if ($unsuspend and confirm_sesskey()) { + require_capability('moodle/user:update', $sitecontext); + + if ($user = $DB->get_record('user', array('id'=>$unsuspend, 'mnethostid'=>$CFG->mnet_localhost_id, 'deleted'=>0))) { + if ($user->suspended != 0) { + $user->suspended = 0; + $user->timemodified = time(); + $DB->set_field('user', 'suspended', $user->suspended, array('id'=>$user->id)); + $DB->set_field('user', 'timemodified', $user->timemodified, array('id'=>$user->id)); + events_trigger('user_updated', $user); + } + } + redirect($returnurl); } // create the user filter form @@ -163,7 +196,7 @@ $strall = get_string('all'); - $baseurl = new moodle_url('user.php', array('sort' => $sort, 'dir' => $dir, 'perpage' => $perpage)); + $baseurl = new moodle_url('/admin/user.php', array('sort' => $sort, 'dir' => $dir, 'perpage' => $perpage)); echo $OUTPUT->paging_bar($usercount, $page, $perpage, $baseurl); flush(); @@ -225,9 +258,7 @@ $table->align[] = 'left'; $table->head[] = $lastaccess; $table->align[] = 'left'; - $table->head[] = ""; - $table->align[] = 'center'; - $table->head[] = ""; + $table->head[] = get_string('edit'); $table->align[] = 'center'; $table->head[] = ""; $table->align[] = 'center'; @@ -238,52 +269,65 @@ continue; // do not display guest here } - if ($user->id == $USER->id or is_siteadmin($user)) { - $deletebutton = ""; - } else { - if (has_capability('moodle/user:delete', $sitecontext)) { - $deletebutton = "id&sesskey=".sesskey()."\">$strdelete"; + $buttons = array(); + $lastcolumn = ''; + + // delete button + if (has_capability('moodle/user:delete', $sitecontext)) { + if (is_mnet_remote_user($user) or $user->id == $USER->id or is_siteadmin($user)) { + // no deleting of self, mnet accounts or admins allowed } else { - $deletebutton =""; + $buttons[] = html_writer::link(new moodle_url($returnurl, array('delete'=>$user->id, 'sesskey'=>sesskey())), html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('t/delete'), 'alt'=>$strdelete, 'class'=>'iconsmall')), array('title'=>$strdelete)); } } - if (has_capability('moodle/user:update', $sitecontext) and (is_siteadmin($USER) or !is_siteadmin($user)) and !is_mnet_remote_user($user)) { - $editbutton = "id&course=$site->id\">$stredit"; - if ($user->confirmed == 0) { - $confirmbutton = "id&sesskey=".sesskey()."\">" . get_string('confirm') . ""; + // suspend button + if (has_capability('moodle/user:update', $sitecontext)) { + if (is_mnet_remote_user($user)) { + // mnet users have special access control, they can not be deleted the standard way or suspended + $accessctrl = 'allow'; + if ($acl = $DB->get_record('mnet_sso_access_control', array('username'=>$user->username, 'mnet_host_id'=>$user->mnethostid))) { + $accessctrl = $acl->accessctrl; + } + $changeaccessto = ($accessctrl == 'deny' ? 'allow' : 'deny'); + $buttons[] = " (id}&accessctrl=$changeaccessto&sesskey=".sesskey()."\">".get_string($changeaccessto, 'mnet') . " access)"; + } else { - $confirmbutton = ""; - } - } else { - $editbutton =""; - if ($user->confirmed == 0) { - $confirmbutton = "".get_string('confirm').""; - } else { - $confirmbutton = ""; + if ($user->suspended) { + $buttons[] = html_writer::link(new moodle_url($returnurl, array('unsuspend'=>$user->id, 'sesskey'=>sesskey())), html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('t/show'), 'alt'=>$strunsuspend, 'class'=>'iconsmall')), array('title'=>$strunsuspend)); + } else { + if ($user->id == $USER->id or is_siteadmin($user)) { + // no suspending of admins or self! + } else { + $buttons[] = html_writer::link(new moodle_url($returnurl, array('suspend'=>$user->id, 'sesskey'=>sesskey())), html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('t/hide'), 'alt'=>$strsuspend, 'class'=>'iconsmall')), array('title'=>$strsuspend)); + } + } + } } - // for remote users, shuffle columns around and display MNET stuff + // edit button + if (has_capability('moodle/user:update', $sitecontext)) { + // prevent editing of admins by non-admins + if (is_siteadmin($USER) or !is_siteadmin($user)) { + $buttons[] = html_writer::link(new moodle_url($securewwwroot.'/user/editadvanced.php', array('id'=>$user->id, 'course'=>$site->id)), html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('t/edit'), 'alt'=>$stredit, 'class'=>'iconsmall')), array('title'=>$stredit)); + } + } + + // the last column - confirm or mnet info if (is_mnet_remote_user($user)) { - $accessctrl = 'allow'; - if ($acl = $DB->get_record('mnet_sso_access_control', array('username'=>$user->username, 'mnet_host_id'=>$user->mnethostid))) { - $accessctrl = $acl->accessctrl; - } - $changeaccessto = ($accessctrl == 'deny' ? 'allow' : 'deny'); - // delete button in confirm column - remote users should already be confirmed - // TODO: no delete for remote users, for now. new userid, delete flag, unique on username/host... - $confirmbutton = ""; - // ACL in delete column - $deletebutton = get_string($accessctrl, 'mnet'); - if (has_capability('moodle/user:delete', $sitecontext)) { - // TODO: this should be under a separate capability - $deletebutton .= " (id}&accessctrl=$changeaccessto&sesskey=".sesskey()."\">" - . get_string($changeaccessto, 'mnet') . " access)"; - } - // mnet info in edit column + // all mnet users are confirmed, let's print just the name of the host there if (isset($mnethosts[$user->mnethostid])) { - $editbutton = $mnethosts[$user->mnethostid]->name; + $lastcolumn = get_string($accessctrl, 'mnet').': '.$mnethosts[$user->mnethostid]->name; + } else { + $lastcolumn = get_string($accessctrl, 'mnet'); + } + + } else if ($user->confirmed == 0) { + if (has_capability('moodle/user:update', $sitecontext)) { + $lastcolumn = html_writer::link(new moodle_url($returnurl, array('confirmuser'=>$user->id, 'sesskey'=>sesskey())), $strconfirm); + } else { + $lastcolumn = "".get_string('confirm').""; } } @@ -302,9 +346,13 @@ $row[] = $user->city; $row[] = $user->country; $row[] = $strlastaccess; - $row[] = $editbutton; - $row[] = $deletebutton; - $row[] = $confirmbutton; + if ($user->suspended) { + foreach ($row as $k=>$v) { + $row[$k] = html_writer::tag('span', $v, array('class'=>'usersuspended')); + } + } + $row[] = implode(' ', $buttons); + $row[] = $lastcolumn; $table->data[] = $row; } } diff --git a/lang/en/admin.php b/lang/en/admin.php index f648a3dbdd8..9b075d0eae3 100644 --- a/lang/en/admin.php +++ b/lang/en/admin.php @@ -924,6 +924,7 @@ $string['supportcontact'] = 'Support contact'; $string['supportemail'] = 'Support email'; $string['supportname'] = 'Support name'; $string['supportpage'] = 'Support page'; +$string['suspenduser'] = 'Suspend user account'; $string['switchlang'] = 'Switch lang directory'; $string['systempaths'] = 'System paths'; $string['tablenosave'] = 'Changes in table above are saved automatically.'; @@ -952,6 +953,7 @@ $string['unicoderecommended'] = 'Storing all your data in Unicode (UTF-8) is rec $string['unicoderequired'] = 'It is required that you store all your data in Unicode format (UTF-8). New installations must be performed into databases that have their default character set as Unicode. If you are upgrading, you should perform the UTF-8 migration process (see the Admin page).'; $string['uninstallplugin'] = 'Uninstall'; $string['unsupported'] = 'Unsupported'; +$string['unsuspenduser'] = 'Activate user account'; $string['updateaccounts'] = 'Update existing accounts'; $string['updatecomponent'] = 'Update component'; $string['upgradestart'] = 'Upgrade'; diff --git a/lang/en/auth.php b/lang/en/auth.php index df576ec8889..72bd8e688f5 100644 --- a/lang/en/auth.php +++ b/lang/en/auth.php @@ -128,6 +128,8 @@ $string['showguestlogin'] = 'You can hide or show the guest login button on the $string['stdchangepassword'] = 'Use standard page for changing password'; $string['stdchangepassword_expl'] = 'If the external authentication system allows password changes through Moodle, switch this to Yes. This setting overrides \'Change Password URL\'.'; $string['stdchangepassword_explldap'] = 'NOTE: It is recommended that you use LDAP over an SSL encrypted tunnel (ldaps://) if the LDAP server is remote.'; +$string['suspended'] = 'Suspended acount'; +$string['suspended_help'] = 'Suspended user accounts cannot log in or use web services, and any outgoing messages are discarded.'; $string['unlocked'] = 'Unlocked'; $string['unlockedifempty'] = 'Unlocked if empty'; $string['update_never'] = 'Never'; diff --git a/lib/datalib.php b/lib/datalib.php index 0a80e0c0bcc..a41945b4ce7 100644 --- a/lib/datalib.php +++ b/lib/datalib.php @@ -314,7 +314,7 @@ function get_users_listing($sort='lastaccess', $dir='ASC', $page=0, $recordsperp // warning: will return UNCONFIRMED USERS return $DB->get_records_sql("SELECT id, username, email, firstname, lastname, city, country, - lastaccess, confirmed, mnethostid$extrafields + lastaccess, confirmed, mnethostid, suspended $extrafields FROM {user} WHERE $select $sort", $params, $page, $recordsperpage); diff --git a/theme/base/style/core.css b/theme/base/style/core.css index 1f4b5602a14..4981c014c7d 100644 --- a/theme/base/style/core.css +++ b/theme/base/style/core.css @@ -34,6 +34,10 @@ a.dimmed_text:visited, .dimmed_text a, .dimmed_text a:link, .dimmed_text a:visited, +.usersuspended, +.usersuspended a, +.usersuspended a:link, +.usersuspended a:visited, .dimmed_category, .dimmed_category a { height: 1%; opacity: 0.5; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter: alpha(opacity=50); } diff --git a/user/editadvanced.php b/user/editadvanced.php index e376086fd68..290aa80bf92 100644 --- a/user/editadvanced.php +++ b/user/editadvanced.php @@ -181,6 +181,12 @@ if ($usernew = $userform->get_data()) { unset_user_preference('create_password', $usernew); // prevent cron from generating the password } } + + // force logout if user just suspended + if (isset($usernew->suspended) and $usernew->suspended and !$user->suspended) { + session_kill_user($user->id); + } + $usercreated = false; } diff --git a/user/editadvanced_form.php b/user/editadvanced_form.php index 742b3dd0fc6..2af0b1c20c2 100644 --- a/user/editadvanced_form.php +++ b/user/editadvanced_form.php @@ -45,6 +45,9 @@ class user_editadvanced_form extends moodleform { $mform->addElement('select', 'auth', get_string('chooseauthmethod','auth'), $auth_options); $mform->addHelpButton('auth', 'chooseauthmethod', 'auth'); + $mform->addElement('advcheckbox', 'suspended', get_string('suspended','auth')); + $mform->addHelpButton('suspended', 'suspended', 'auth'); + if (!empty($CFG->passwordpolicy)){ $mform->addElement('static', 'passwordpolicyinfo', '', print_password_policy()); } @@ -92,6 +95,9 @@ class user_editadvanced_form extends moodleform { // admin must choose some password and supply correct email if (!empty($USER->newadminuser)) { $mform->addRule('newpassword', get_string('required'), 'required', null, 'client'); + if ($mform->elementExists('suspended')) { + $mform->removeElement('suspended'); + } } // require password for new users @@ -99,6 +105,19 @@ class user_editadvanced_form extends moodleform { $mform->addRule('newpassword', get_string('required'), 'required', null, 'client'); } + if ($user and is_mnet_remote_user($user)) { + // only local accounts can be suspended + if ($mform->elementExists('suspended')) { + $mform->removeElement('suspended'); + } + } + if ($user and ($user->id == $USER->id or is_siteadmin($user))) { + // prevent self and admin mess ups + if ($mform->elementExists('suspended')) { + $mform->hardFreeze('suspended'); + } + } + // print picture if (!empty($CFG->gdversion) and empty($USER->newadminuser)) { if ($user) { diff --git a/user/filters/lib.php b/user/filters/lib.php index 91bc1137839..6c6a8395be7 100644 --- a/user/filters/lib.php +++ b/user/filters/lib.php @@ -35,7 +35,7 @@ class user_filtering { if (empty($fieldnames)) { $fieldnames = array('realname'=>0, 'lastname'=>1, 'firstname'=>1, 'email'=>1, 'city'=>1, 'country'=>1, - 'confirmed'=>1, 'profile'=>1, 'courserole'=>1, 'systemrole'=>1, 'cohort'=>1, + 'confirmed'=>1, 'suspended'=>1, 'profile'=>1, 'courserole'=>1, 'systemrole'=>1, 'cohort'=>1, 'firstaccess'=>1, 'lastaccess'=>1, 'neveraccessed'=>1, 'timemodified'=>1, 'nevermodified'=>1, 'username'=>1, 'auth'=>1, 'mnethostid'=>1); } @@ -110,6 +110,7 @@ class user_filtering { case 'city': return new user_filter_text('city', get_string('city'), $advanced, 'city'); case 'country': return new user_filter_select('country', get_string('country'), $advanced, 'country', get_string_manager()->get_list_of_countries(), $USER->country); case 'confirmed': return new user_filter_yesno('confirmed', get_string('confirmed', 'admin'), $advanced, 'confirmed'); + case 'suspended': return new user_filter_yesno('suspended', get_string('suspended', 'auth'), $advanced, 'suspended'); case 'profile': return new user_filter_profilefield('profile', get_string('profile'), $advanced); case 'courserole': return new user_filter_courserole('courserole', get_string('courserole', 'filters'), $advanced); case 'systemrole': return new user_filter_globalrole('systemrole', get_string('globalrole', 'role'), $advanced); diff --git a/user/profile.php b/user/profile.php index e29090179a7..3f619d36375 100644 --- a/user/profile.php +++ b/user/profile.php @@ -347,6 +347,12 @@ if (!empty($CFG->usetags)) { } } +if (!isset($hiddenfields['suspended'])) { + if ($user->suspended) { + print_row('', get_string('suspended', 'auth')); + } +} + echo ""; diff --git a/user/view.php b/user/view.php index 87f3a00d8b1..cb534911bc4 100644 --- a/user/view.php +++ b/user/view.php @@ -315,6 +315,12 @@ if (!isset($hiddenfields['mycourses'])) { } } +if (!isset($hiddenfields['suspended'])) { + if ($user->suspended) { + print_row('', get_string('suspended', 'auth')); + } +} + echo ""; // Print messaging link if allowed