Merge branch 'w35_MDL-35064_m24_delenrol' of git://github.com/skodak/moodle

Conflicts:
	enrol/manual/locallib.php
This commit is contained in:
Aparup Banerjee 2012-08-29 13:46:04 +08:00
commit 8be5407bc1
4 changed files with 352 additions and 8 deletions

View File

@ -23,12 +23,15 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('NO_OUTPUT_BUFFERING', true);
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
$action = required_param('action', PARAM_ALPHANUMEXT);
$enrol = required_param('enrol', PARAM_PLUGIN);
$confirm = optional_param('confirm', 0, PARAM_BOOL);
$migrate = optional_param('migrate', 0, PARAM_BOOL);
$PAGE->set_url('/admin/enrol.php');
$PAGE->set_context(context_system::instance());
@ -94,24 +97,58 @@ switch ($action) {
break;
case 'uninstall':
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('enrolments', 'enrol'));
if (get_string_manager()->string_exists('pluginname', 'enrol_'.$enrol)) {
$strplugin = get_string('pluginname', 'enrol_'.$enrol);
} else {
$strplugin = $enrol;
}
echo $PAGE->set_title($strplugin);
echo $OUTPUT->header();
if (!$confirm) {
$uurl = new moodle_url('/admin/enrol.php', array('action'=>'uninstall', 'enrol'=>$enrol, 'sesskey'=>sesskey(), 'confirm'=>1));
echo $OUTPUT->confirm(get_string('uninstallconfirm', 'enrol', $strplugin), $uurl, $return);
echo $OUTPUT->heading(get_string('enrolments', 'enrol'));
$deleteurl = new moodle_url('/admin/enrol.php', array('action'=>'uninstall', 'enrol'=>$enrol, 'sesskey'=>sesskey(), 'confirm'=>1, 'migrate'=>0));
$migrateurl = new moodle_url('/admin/enrol.php', array('action'=>'uninstall', 'enrol'=>$enrol, 'sesskey'=>sesskey(), 'confirm'=>1, 'migrate'=>1));
$migrate = new single_button($migrateurl, get_string('uninstallmigrate', 'enrol'));
$delete = new single_button($deleteurl, get_string('uninstalldelete', 'enrol'));
$cancel = new single_button($return, get_string('cancel'), 'get');
$buttons = $OUTPUT->render($delete) . $OUTPUT->render($cancel);
if ($enrol !== 'manual') {
$buttons = $OUTPUT->render($migrate) . $buttons;
}
echo $OUTPUT->box_start('generalbox', 'notice');
echo html_writer::tag('p', markdown_to_html(get_string('uninstallconfirm', 'enrol', $strplugin)));
echo html_writer::tag('div', $buttons, array('class' => 'buttons'));
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
exit;
} else { // Delete everything!!
} else {
// This may take a long time.
set_time_limit(0);
// Disable plugin to prevent concurrent cron execution.
unset($enabled[$enrol]);
set_config('enrol_plugins_enabled', implode(',', array_keys($enabled)));
if ($migrate) {
echo $OUTPUT->heading(get_string('uninstallmigrating', 'enrol', 'enrol_'.$enrol));
require_once("$CFG->dirroot/enrol/manual/locallib.php");
enrol_manual_migrate_plugin_enrolments($enrol);
echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
}
// Delete everything!!
uninstall_plugin('enrol', $enrol);
$syscontext->mark_dirty(); // resets all enrol caches
$syscontext->mark_dirty(); // Resets all enrol caches.
$a = new stdClass();
$a->plugin = $strplugin;

View File

@ -352,3 +352,101 @@ class enrol_manual_deleteselectedusers_operation extends enrol_bulk_enrolment_op
return true;
}
}
/**
* Migrates all enrolments of the given plugin to enrol_manual plugin,
* this is used for example during plugin uninstallation.
*
* NOTE: this function does not trigger role and enrolment related events.
*
* @param string $enrol The enrolment method.
*/
function enrol_manual_migrate_plugin_enrolments($enrol) {
global $DB;
if ($enrol === 'manual') {
// We can not migrate to self.
return;
}
$manualplugin = enrol_get_plugin('manual');
$params = array('enrol'=>$enrol);
$sql = "SELECT e.id, e.courseid, e.status, MIN(me.id) AS mid, COUNT(ue.id) AS cu
FROM {enrol} e
JOIN {user_enrolments} ue ON (ue.enrolid = e.id)
JOIN {course} c ON (c.id = e.courseid)
LEFT JOIN {enrol} me ON (me.courseid = e.courseid AND me.enrol='manual')
WHERE e.enrol = :enrol
GROUP BY e.id, e.courseid, e.status
ORDER BY e.id";
$rs = $DB->get_recordset_sql($sql, $params);
foreach($rs as $e) {
$minstance = false;
if (!$e->mid) {
// Manual instance does not exist yet, add a new one.
$course = $DB->get_record('course', array('id'=>$e->courseid), '*', MUST_EXIST);
if ($minstance = $DB->get_record('enrol', array('courseid'=>$course->id, 'enrol'=>'manual'))) {
// Already created by previous iteration.
$e->mid = $minstance->id;
} else if ($e->mid = $manualplugin->add_default_instance($course)) {
$minstance = $DB->get_record('enrol', array('id'=>$e->mid));
if ($e->status != ENROL_INSTANCE_ENABLED) {
$DB->set_field('enrol', 'status', ENROL_INSTANCE_DISABLED, array('id'=>$e->mid));
$minstance->status = ENROL_INSTANCE_DISABLED;
}
}
} else {
$minstance = $DB->get_record('enrol', array('id'=>$e->mid));
}
if (!$minstance) {
// This should never happen unless adding of default instance fails unexpectedly.
continue;
}
// First delete potential role duplicates.
$params = array('id'=>$e->id, 'component'=>'enrol_'.$enrol, 'empty'=>$DB->sql_empty());
$sql = "SELECT ra.id
FROM {role_assignments} ra
JOIN {role_assignments} mra ON (mra.contextid = ra.contextid AND mra.userid = ra.userid AND mra.roleid = ra.roleid AND mra.component = :empty AND mra.itemid = 0)
WHERE ra.component = :component AND ra.itemid = :id";
$ras = $DB->get_records_sql($sql, $params);
$ras = array_keys($ras);
$DB->delete_records_list('role_assignments', 'id', $ras);
unset($ras);
// Migrate roles.
$sql = "UPDATE {role_assignments}
SET itemid = 0, component = :empty
WHERE itemid = :id AND component = :component";
$params = array('empty'=>$DB->sql_empty(), 'id'=>$e->id, 'component'=>'enrol_'.$enrol);
$DB->execute($sql, $params);
// Delete potential enrol duplicates.
$params = array('id'=>$e->id, 'mid'=>$e->mid);
$sql = "SELECT ue.id
FROM {user_enrolments} ue
JOIN {user_enrolments} mue ON (mue.userid = ue.userid AND mue.enrolid = :mid)
WHERE ue.enrolid = :id";
$ues = $DB->get_records_sql($sql, $params);
$ues = array_keys($ues);
$DB->delete_records_list('user_enrolments', 'id', $ues);
unset($ues);
// Migrate to manual enrol instance.
$params = array('id'=>$e->id, 'mid'=>$e->mid);
if ($e->status != ENROL_INSTANCE_ENABLED and $minstance->status == ENROL_INSTANCE_ENABLED) {
$status = ", status = :disabled";
$params['disabled'] = ENROL_USER_SUSPENDED;
} else {
$status = "";
}
$sql = "UPDATE {user_enrolments}
SET enrolid = :mid $status
WHERE enrolid = :id";
$DB->execute($sql, $params);
}
$rs->close();
}

View File

@ -0,0 +1,204 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Manual enrolment tests.
*
* @package enrol_manual
* @category phpunit
* @copyright 2012 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Manual enrolment tests.
*
* @package enrol_manual
* @category phpunit
* @copyright 2012 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class enrol_manual_lib_testcase extends advanced_testcase {
/**
* Test enrol migration function used when uninstalling enrol plugins.
*/
public function test_migrate_plugin_enrolments() {
global $DB, $CFG;
require_once($CFG->dirroot.'/enrol/manual/locallib.php');
$this->resetAfterTest();
$manplugin = enrol_get_plugin('manual');
// Setup a few courses and users.
$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->assertNotEmpty($studentrole);
$teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
$this->assertNotEmpty($teacherrole);
$course1 = $this->getDataGenerator()->create_course();
$course2 = $this->getDataGenerator()->create_course();
$course3 = $this->getDataGenerator()->create_course();
$course4 = $this->getDataGenerator()->create_course();
$course5 = $this->getDataGenerator()->create_course();
$context1 = context_course::instance($course1->id);
$context2 = context_course::instance($course2->id);
$context3 = context_course::instance($course3->id);
$context4 = context_course::instance($course4->id);
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();
$user4 = $this->getDataGenerator()->create_user();
// We expect manual, self and guest instances to be created by default.
$this->assertEquals(5, $DB->count_records('enrol', array('enrol'=>'manual')));
$this->assertEquals(5, $DB->count_records('enrol', array('enrol'=>'self')));
$this->assertEquals(5, $DB->count_records('enrol', array('enrol'=>'guest')));
$this->assertEquals(15, $DB->count_records('enrol', array()));
$this->assertEquals(0, $DB->count_records('user_enrolments', array()));
// Enrol some users to manual instances.
$maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
$DB->set_field('enrol', 'status', ENROL_INSTANCE_DISABLED, array('id'=>$maninstance1->id));
$maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
$maninstance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual'), '*', MUST_EXIST);
$DB->delete_records('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual'));
$DB->delete_records('enrol', array('courseid'=>$course4->id, 'enrol'=>'manual'));
$DB->delete_records('enrol', array('courseid'=>$course5->id, 'enrol'=>'manual'));
$manplugin->enrol_user($maninstance1, $user1->id, $studentrole->id);
$manplugin->enrol_user($maninstance1, $user2->id, $studentrole->id);
$manplugin->enrol_user($maninstance1, $user3->id, $teacherrole->id);
$manplugin->enrol_user($maninstance2, $user3->id, $teacherrole->id);
$this->assertEquals(4, $DB->count_records('user_enrolments', array()));
// Set up some bogus enrol plugin instances and enrolments.
$xxxinstance1 = $DB->insert_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'xxx', 'status'=>ENROL_INSTANCE_ENABLED));
$xxxinstance1 = $DB->get_record('enrol', array('id'=>$xxxinstance1));
$xxxinstance3 = $DB->insert_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'xxx', 'status'=>ENROL_INSTANCE_DISABLED));
$xxxinstance3 = $DB->get_record('enrol', array('id'=>$xxxinstance3));
$xxxinstance4 = $DB->insert_record('enrol', array('courseid'=>$course4->id, 'enrol'=>'xxx', 'status'=>ENROL_INSTANCE_ENABLED));
$xxxinstance4 = $DB->get_record('enrol', array('id'=>$xxxinstance4));
$xxxinstance4b = $DB->insert_record('enrol', array('courseid'=>$course4->id, 'enrol'=>'xxx', 'status'=>ENROL_INSTANCE_DISABLED));
$xxxinstance4b = $DB->get_record('enrol', array('id'=>$xxxinstance4b));
$DB->insert_record('user_enrolments', array('enrolid'=>$xxxinstance1->id, 'userid'=>$user1->id, 'status'=>ENROL_USER_SUSPENDED));
role_assign($studentrole->id, $user1->id, $context1->id, 'enrol_xxx', $xxxinstance1->id);
role_assign($teacherrole->id, $user1->id, $context1->id, 'enrol_xxx', $xxxinstance1->id);
$DB->insert_record('user_enrolments', array('enrolid'=>$xxxinstance1->id, 'userid'=>$user4->id, 'status'=>ENROL_USER_ACTIVE));
role_assign($studentrole->id, $user4->id, $context1->id, 'enrol_xxx', $xxxinstance1->id);
$this->assertEquals(2, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance1->id)));
$this->assertEquals(6, $DB->count_records('role_assignments', array('contextid'=>$context1->id)));
$DB->insert_record('user_enrolments', array('enrolid'=>$xxxinstance3->id, 'userid'=>$user1->id, 'status'=>ENROL_USER_ACTIVE));
role_assign($studentrole->id, $user1->id, $context3->id, 'enrol_xxx', $xxxinstance3->id);
$DB->insert_record('user_enrolments', array('enrolid'=>$xxxinstance3->id, 'userid'=>$user2->id, 'status'=>ENROL_USER_SUSPENDED));
$this->assertEquals(2, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance3->id)));
$this->assertEquals(1, $DB->count_records('role_assignments', array('contextid'=>$context3->id)));
$DB->insert_record('user_enrolments', array('enrolid'=>$xxxinstance4->id, 'userid'=>$user1->id, 'status'=>ENROL_USER_ACTIVE));
role_assign($studentrole->id, $user1->id, $context4->id, 'enrol_xxx', $xxxinstance4->id);
$DB->insert_record('user_enrolments', array('enrolid'=>$xxxinstance4->id, 'userid'=>$user2->id, 'status'=>ENROL_USER_ACTIVE));
role_assign($studentrole->id, $user2->id, $context4->id, 'enrol_xxx', $xxxinstance4->id);
$DB->insert_record('user_enrolments', array('enrolid'=>$xxxinstance4b->id, 'userid'=>$user1->id, 'status'=>ENROL_USER_SUSPENDED));
role_assign($teacherrole->id, $user1->id, $context4->id, 'enrol_xxx', $xxxinstance4b->id);
$DB->insert_record('user_enrolments', array('enrolid'=>$xxxinstance4b->id, 'userid'=>$user4->id, 'status'=>ENROL_USER_ACTIVE));
role_assign($teacherrole->id, $user4->id, $context4->id, 'enrol_xxx', $xxxinstance4b->id);
$this->assertEquals(2, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance4->id)));
$this->assertEquals(2, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance4b->id)));
$this->assertEquals(4, $DB->count_records('role_assignments', array('contextid'=>$context4->id)));
// Finally do the migration.
enrol_manual_migrate_plugin_enrolments('xxx');
// Verify results.
$this->assertEquals(1, $DB->count_records('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual')));
$this->assertEquals(1, $DB->count_records('enrol', array('courseid'=>$course1->id, 'enrol'=>'xxx')));
$maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
$this->assertEquals(ENROL_INSTANCE_DISABLED, $maninstance1->status);
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance1->id, 'userid'=>$user1->id, 'status'=>ENROL_USER_ACTIVE)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance1->id, 'userid'=>$user2->id, 'status'=>ENROL_USER_ACTIVE)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance1->id, 'userid'=>$user3->id, 'status'=>ENROL_USER_ACTIVE)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance1->id, 'userid'=>$user4->id, 'status'=>ENROL_USER_ACTIVE)));
$this->assertEquals(4, $DB->count_records('user_enrolments', array('enrolid'=>$maninstance1->id)));
$this->assertEquals(0, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance1->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user1->id, 'roleid'=>$studentrole->id, 'contextid'=>$context1->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user1->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context1->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user2->id, 'roleid'=>$studentrole->id, 'contextid'=>$context1->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user3->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context1->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user4->id, 'roleid'=>$studentrole->id, 'contextid'=>$context1->id)));
$this->assertEquals(5, $DB->count_records('role_assignments', array('contextid'=>$context1->id)));
$this->assertEquals(1, $DB->count_records('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual')));
$this->assertEquals(0, $DB->count_records('enrol', array('courseid'=>$course2->id, 'enrol'=>'xxx')));
$maninstance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual'), '*', MUST_EXIST);
$this->assertEquals(ENROL_INSTANCE_ENABLED, $maninstance2->status);
$this->assertEquals(1, $DB->count_records('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual')));
$this->assertEquals(1, $DB->count_records('enrol', array('courseid'=>$course3->id, 'enrol'=>'xxx')));
$maninstance3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual'), '*', MUST_EXIST);
$this->assertEquals(ENROL_INSTANCE_DISABLED, $maninstance3->status);
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance3->id, 'userid'=>$user1->id, 'status'=>ENROL_USER_ACTIVE)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance3->id, 'userid'=>$user2->id, 'status'=>ENROL_USER_SUSPENDED)));
$this->assertEquals(2, $DB->count_records('user_enrolments', array('enrolid'=>$maninstance3->id)));
$this->assertEquals(0, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance3->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user1->id, 'roleid'=>$studentrole->id, 'contextid'=>$context3->id)));
$this->assertEquals(1, $DB->count_records('role_assignments', array('contextid'=>$context3->id)));
$this->assertEquals(1, $DB->count_records('enrol', array('courseid'=>$course4->id, 'enrol'=>'manual')));
$this->assertEquals(2, $DB->count_records('enrol', array('courseid'=>$course4->id, 'enrol'=>'xxx')));
$maninstance4 = $DB->get_record('enrol', array('courseid'=>$course4->id, 'enrol'=>'manual'), '*', MUST_EXIST);
$this->assertEquals(ENROL_INSTANCE_ENABLED, $maninstance4->status);
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance4->id, 'userid'=>$user1->id, 'status'=>ENROL_USER_ACTIVE)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance4->id, 'userid'=>$user2->id, 'status'=>ENROL_USER_ACTIVE)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance4->id, 'userid'=>$user4->id, 'status'=>ENROL_USER_SUSPENDED)));
$this->assertEquals(3, $DB->count_records('user_enrolments', array('enrolid'=>$maninstance4->id)));
$this->assertEquals(0, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance4->id)));
$this->assertEquals(0, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance4b->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user1->id, 'roleid'=>$studentrole->id, 'contextid'=>$context4->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user1->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context4->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user2->id, 'roleid'=>$studentrole->id, 'contextid'=>$context4->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user4->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context4->id)));
$this->assertEquals(4, $DB->count_records('role_assignments', array('contextid'=>$context4->id)));
$this->assertEquals(0, $DB->count_records('enrol', array('courseid'=>$course5->id, 'enrol'=>'manual')));
$this->assertEquals(0, $DB->count_records('enrol', array('courseid'=>$course5->id, 'enrol'=>'xxx')));
// Make sure wrong params do not produce errors or notices.
enrol_manual_migrate_plugin_enrolments('manual');
enrol_manual_migrate_plugin_enrolments('yyyy');
}
}

View File

@ -98,8 +98,13 @@ $string['unenrolconfirm'] = 'Do you really want to unenrol user "{$a->user}" fro
$string['unenrolme'] = 'Unenrol me from {$a}';
$string['unenrolnotpermitted'] = 'You do not have permission or can not unenrol this user from this course.';
$string['unenrolroleusers'] = 'Unenrol users';
$string['uninstallconfirm'] = 'You are about to completely delete the enrol plugin \'{$a}\'. This will completely delete everything in the database associated with this enrolment type. Are you SURE you want to continue?';
$string['uninstallconfirm'] = 'You are about to uninstall the enrolment plugin \'{$a}\'. This will result in the deletion of all data associated with this enrolment type, including users\' grades, group membership, forum subscriptions and any other course-related data.
Are you SURE you want to continue?';
$string['uninstalldelete'] = 'Delete all enrolments and uninstall';
$string['uninstalldeletefiles'] = 'All data associated with the enrol plugin \'{$a->plugin}\' has been deleted from the database. To complete the deletion (and prevent the plugin re-installing itself), you should now delete this directory from your server: {$a->directory}';
$string['uninstallmigrate'] = 'Uninstall but keep all enrolments';
$string['uninstallmigrating'] = 'Migrating "{$a}" enrolments';
$string['unknowajaxaction'] = 'Unknown action requested';
$string['unlimitedduration'] = 'Unlimited';
$string['usersearch'] = 'Search ';