MDL-65061 enrol: Add suspend and other behaviours to IMS enrol plugin

Change-Id: Ia169a8c1dae9c6132d40158ac2a3e346dc3f5e1e
Co-authored-by: Sarah Cotton <sarah.cotton@catalyst-eu.net>
Co-authored-by: Mark Johnson <mark.johnson@catalyst-eu.net>
This commit is contained in:
Segun Babalola 2022-07-12 18:53:46 +01:00 committed by Mark Johnson
parent b077af7e89
commit 73cb052158
4 changed files with 767 additions and 9 deletions

View File

@ -93,3 +93,9 @@ $string['roles'] = 'Roles';
$string['ignore'] = 'Ignore';
$string['importimsfile'] = 'Import IMS Enterprise file';
$string['privacy:metadata'] = 'The IMS Enterprise file enrolment plugin does not store any personal data.';
$string['unenrolaction'] = 'Unenrol action';
$string['unenrolaction_desc'] = 'Action to be taken when a user is unenrolled from a course (only applied when the <strong>unenrol</strong> setting above is active)';
$string['disableenrolonly'] = 'Suspend enrolment only';
$string['disableenrolmentandremoveallroles'] = 'Suspend enrolment & remove roles';
$string['noaction'] = 'No action';
$string['removeenrolmentandallroles'] = 'Delete enrolment & roles';

View File

@ -584,7 +584,11 @@ class enrol_imsenterprise_plugin extends enrol_plugin {
$this->log_line("Created user record ('.$id.') for user '$person->username' (ID number $person->idnumber).");
}
} else if ($createnewusers) {
$this->log_line("User record already exists for user '$person->username' (ID number $person->idnumber).");
$username = $person->username ?? "[unknown username]";
$personnumber = $person->idnumber ?? "[unknown ID number]";
$this->log_line("User record already exists for user '" . $username . "' (ID number " . $personnumber . ").");
// It is totally wrong to mess with deleted users flag directly in database!!!
// There is no official way to undelete user, sorry..
@ -683,10 +687,12 @@ class enrol_imsenterprise_plugin extends enrol_plugin {
// Decide the "real" role (i.e. the Moodle role) that this user should be assigned to.
// Zero means this roletype is supposed to be skipped.
$moodleroleid = $this->rolemappings[$member->roletype];
$moodleroleid = (isset($member->roletype) && isset($this->rolemappings[$member->roletype]))
? $this->rolemappings[$member->roletype] : null;
if (!$moodleroleid) {
$this->log_line("SKIPPING role $member->roletype for $memberstoreobj->userid "
."($member->idnumber) in course $memberstoreobj->course");
$this->log_line("SKIPPING role " .
($member->roletype ?? "[]") . " for $memberstoreobj->userid " .
"($member->idnumber) in course $memberstoreobj->course");
continue;
}
@ -741,25 +747,80 @@ class enrol_imsenterprise_plugin extends enrol_plugin {
} else if ($this->get_config('imsunenrol')) {
// Unenrol member.
$unenrolsetting = $this->get_config('unenrolaction');
$einstances = $DB->get_records('enrol',
array('enrol' => $memberstoreobj->enrol, 'courseid' => $courseobj->id));
foreach ($einstances as $einstance) {
// Unenrol the user from all imsenterprise enrolment instances.
$this->unenrol_user($einstance, $memberstoreobj->userid);
switch ($unenrolsetting) {
case ENROL_EXT_REMOVED_SUSPEND:
case ENROL_EXT_REMOVED_SUSPENDNOROLES: {
foreach ($einstances as $einstance) {
$this->update_user_enrol($einstance, $memberstoreobj->userid,
ENROL_USER_SUSPENDED, $timeframe->begin, $timeframe->end);
$this->log_line("Suspending user enrolment for $member->idnumber in " .
" course $ship->coursecode ");
if (intval($unenrolsetting) === intval(ENROL_EXT_REMOVED_SUSPENDNOROLES)) {
if (!$context =
context_course::instance($courseobj->id, IGNORE_MISSING)) {
$this->log_line("Unable to process IMS unenrolment request " .
" because course context not found. User: " .
"#$memberstoreobj->userid ($member->idnumber) , " .
" course: $memberstoreobj->course");
} else {
role_unassign_all([
'contextid' => $context->id,
'userid' => $memberstoreobj->userid,
'component' => 'enrol_imsenterprise',
'itemid' => $einstance->id
]);
$this->log_line("Removing role assignments for user " .
"$member->idnumber from role $moodleroleid in course " .
"$ship->coursecode ");
}
}
}
}
break;
case ENROL_EXT_REMOVED_UNENROL: {
foreach ($einstances as $einstance) {
$this->unenrol_user($einstance, $memberstoreobj->userid);
$this->log_line("Removing user enrolment record for $member->idnumber " .
" in course $ship->coursecode ");
}
}
break;
case ENROL_EXT_REMOVED_KEEP: {
$this->log_line("Processed KEEP IMS unenrol instruction (i.e. do nothing)");
}
break;
default:
$this->log_line("Unable to process IMS unenrolment request because " .
" the value set for plugin parameter, unenrol action, is not recognised. " .
" User: #$memberstoreobj->userid ($member->idnumber) " .
" , course: $memberstoreobj->course");
break;
}
$membersuntally++;
$this->log_line("Unenrolled $member->idnumber from role $moodleroleid in course");
}
}
}
$this->log_line("Added $memberstally users to course $ship->coursecode");
if ($membersuntally > 0) {
$this->log_line("Removed $membersuntally users from course $ship->coursecode");
$this->log_line("Processed $membersuntally unenrol instructions for course $ship->coursecode");
}
}
} // End process_membership_tag().
/**

View File

@ -111,6 +111,21 @@ if ($ADMIN->fulltree) {
$settings->add(new admin_setting_configcheckbox('enrol_imsenterprise/imsunenrol',
get_string('allowunenrol', 'enrol_imsenterprise'), get_string('allowunenrol_desc', 'enrol_imsenterprise'), 0));
/* Action to take when a request to remove a user enrolment record is detected in the IMS file */
$options = [
ENROL_EXT_REMOVED_KEEP => get_string('noaction', 'enrol_imsenterprise'),
ENROL_EXT_REMOVED_UNENROL => get_string('removeenrolmentandallroles', 'enrol_imsenterprise'),
ENROL_EXT_REMOVED_SUSPEND => get_string('disableenrolonly', 'enrol_imsenterprise'),
ENROL_EXT_REMOVED_SUSPENDNOROLES => get_string('disableenrolmentandremoveallroles', 'enrol_imsenterprise'),
];
$settings->add(
new admin_setting_configselect('enrol_imsenterprise/unenrolaction',
get_string('unenrolaction', 'enrol_imsenterprise'),
get_string('unenrolaction_desc', 'enrol_imsenterprise'),
ENROL_EXT_REMOVED_UNENROL, $options)
);
if (!during_initial_install()) {
$imscourses = new imsenterprise_courses();
foreach ($imscourses->get_courseattrs() as $courseattr) {

View File

@ -0,0 +1,676 @@
<?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/>.
namespace enrol_imsenterprise;
use core_course_category;
use enrol_imsenterprise_plugin;
use stdClass;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/enrol/imsenterprise/locallib.php');
require_once($CFG->dirroot . '/enrol/imsenterprise/lib.php');
/**
* IMS Enterprise test case
*
* @package enrol_imsenterprise
* @category test
* @copyright 2019 Segun Babalola
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @covers \enrol_imsenterprise_plugin
*/
class imsenterprise_unenrol_test extends \advanced_testcase {
/**
* @var $imsplugin enrol_imsenterprise_plugin IMS plugin instance.
*/
public $imsplugin;
/**
* Setup required for all tests.
*/
protected function setUp(): void {
$this->resetAfterTest(true);
$this->imsplugin = enrol_get_plugin('imsenterprise');
$this->set_test_config();
}
/**
* Sets the plugin configuration for testing
*/
public function set_test_config() {
$this->imsplugin->set_config('mailadmins', false);
$this->imsplugin->set_config('prev_path', '');
$this->imsplugin->set_config('createnewusers', true);
$this->imsplugin->set_config('imsupdateusers', true);
$this->imsplugin->set_config('createnewcourses', true);
$this->imsplugin->set_config('updatecourses', true);
$this->imsplugin->set_config('createnewcategories', true);
$this->imsplugin->set_config('categoryseparator', '');
$this->imsplugin->set_config('categoryidnumber', false);
$this->imsplugin->set_config('nestedcategories', false);
}
/**
* Creates an IMS enterprise XML file and adds it's path to config settings.
*
* @param bool|array $users false or array of users StdClass
* @param bool|array $courses false or of courses StdClass
* @param bool|array $usercoursemembership false or of courses StdClass
*/
public function set_xml_file($users = false, $courses = false, $usercoursemembership = false) {
$xmlcontent = '<enterprise>';
// Users.
if (!empty($users) && is_array($users)) {
foreach ($users as $user) {
$xmlcontent .= '<person' . (!empty($user->recstatus) ? ' recstatus="'.$user->recstatus.'"' : '').'>';
$xmlcontent .= '<sourcedid><source>TestSource</source><id>'.$user->idnumber.'</id></sourcedid>';
$xmlcontent .= '<userid' . (!empty($user->auth) ? ' authenticationtype="'.$user->auth.'"' : '');
$xmlcontent .= '>'.$user->username.'</userid>';
$xmlcontent .= '<name>'
.'<fn>'.$user->firstname.' '.$user->lastname.'</fn>'
.'<n><family>'.$user->lastname.'</family><given>'.$user->firstname.'</given></n>'
.'</name>'
.'<email>'.$user->email.'</email>';
$xmlcontent .= '</person>';
}
}
// Courses.
// Mapping based on default course attributes - IMS group tags mapping.
if (!empty($courses) && is_array($courses)) {
foreach ($courses as $course) {
$xmlcontent .= '<group' . (!empty($course->recstatus) ? ' recstatus="'.$course->recstatus.'"' : '').'>';
$xmlcontent .= '<sourcedid><source>TestSource</source><id>'.$course->idnumber.'</id></sourcedid>';
$xmlcontent .= '<description>'.(!empty($course->imsshort) ? '<short>'.$course->imsshort.'</short>' : '');
$xmlcontent .= (!empty($course->imslong) ? '<long>'.$course->imslong.'</long>' : '');
$xmlcontent .= (!empty($course->imsfull) ? '<full>'.$course->imsfull.'</full>' : '');
$xmlcontent .= '</description>';
// The orgunit tag value is used by moodle as category name.
$xmlcontent .= '<org>';
// Optional category name.
if (isset($course->category)) {
if (is_array($course->category)) {
foreach ($course->category as $category) {
$xmlcontent .= '<orgunit>' . $category . '</orgunit>';
}
} else if (is_object($course->category)) {
$xmlcontent .= '<orgunit>' . $course->category->name . '</orgunit>';
} else if (!empty($course->category)) {
$xmlcontent .= '<orgunit>' . $course->category . '</orgunit>';
}
}
$xmlcontent .= '</org>';
$xmlcontent .= '</group>';
}
}
// User course membership (i.e. roles and enrolments).
if (!empty($usercoursemembership) && is_array($usercoursemembership)) {
foreach ($usercoursemembership as $crsemship) {
// Only process records that have a source/id (i.e. course code) set in the IMS file.
// Note that we could also check that there is a corresponding $course with the course code given here,
// however it is possible that we want to test the behaviour of orphan membership elements in future,
// so leaving the check out for now.
if (isset($crsemship->crseidnumber) && isset($crsemship->member) && is_array($crsemship->member)
&& count($crsemship->member)) {
$xmlcontent .= '<membership><sourcedid><source>TestSource</source><id>'
.$crsemship->crseidnumber . '</id></sourcedid>';
foreach ($crsemship->member as $crsemember) {
if (!empty($crsemember->useridnumber)) {
$xmlcontent .= '<member>';
$xmlcontent .= '<sourcedid><source>TestSource</source><id>'. $crsemember->useridnumber
.'</id></sourcedid>';
// Indicates whether the member is a Person (1) or another Group (2).
// We're only handling user membership here, so hard-code value of 1.
$xmlcontent .= '<idtype>1</idtype>';
if (isset($crsemember->role) && is_array($crsemember->role)) {
foreach ($crsemember->role as $role) {
$xmlcontent .= '<role roletype="'.$role->roletype.'" recstatus="'.$role->recstatus.'">';
$xmlcontent .= '<userid/>';
$xmlcontent .= '<status>' . $role->rolestatus . '</status>';
$xmlcontent .= '</role>';
}
}
$xmlcontent .= '</member>';
}
}
$xmlcontent .= '</membership>';
}
}
}
$xmlcontent .= '</enterprise>';
// Creating the XML file.
$filename = 'ims_' . rand(1000, 9999) . '.xml';
$tmpdir = make_temp_directory('enrol_imsenterprise');
$xmlfilepath = $tmpdir . '/' . $filename;
file_put_contents($xmlfilepath, $xmlcontent);
// Setting the file path in CFG.
$this->imsplugin->set_config('imsfilelocation', $xmlfilepath);
}
/**
* Utility function for generating test user records
*
* @param int $numberofrecordsrequired - number of test users required
* @return array of StdClass objects representing test user records
*/
private function generate_test_user_records($numberofrecordsrequired) {
$users = [];
for ($i = 0; $i < $numberofrecordsrequired; $i++) {
$usernumber = $i + 101;
$users[] = (object)[
'recstatus' => enrol_imsenterprise_plugin::IMSENTERPRISE_ADD,
'idnumber' => $usernumber,
'username' => 'UID' .$usernumber,
'email' => 'user' . $usernumber . '@moodle.org',
'firstname' => 'User' . $usernumber . ' firstname',
'lastname' => 'User' . $usernumber . ' lastname'
];
}
return $users;
}
/**
* Utility function for generating test course records
*
* @param int $numberofrecordsrequired - number of test course records required
* @return array of StdClass objects representing test course records
*/
private function generate_test_course_records($numberofrecordsrequired) {
$courses = [];
for ($i = 0; $i < $numberofrecordsrequired; $i++) {
$coursenumber = $i + 101;
$courses[] = (object)[
'recstatus' => enrol_imsenterprise_plugin::IMSENTERPRISE_ADD,
'idnumber' => 'CID' . $coursenumber,
'imsshort' => 'Course ' . $coursenumber,
'category' => core_course_category::get_default()
];
}
return $courses;
}
/**
* Utility function for generating test membership structure for given users and courses.
* Linkmatrix is expected to be in [row, col] format, where courses are rows and users are columns.
* Each element of the link matrix is expected to contain <roletype>:<role status>:<role recstatus>.
*
* @param array $users
* @param array $courses
* @param array $linkmatrix - matrix/two dimensional array of required user course enrolments
* @return array
*/
private function link_users_with_courses($users, $courses, $linkmatrix) {
$memberships = [];
foreach ($courses as $i => $c) {
$membership = new stdClass();
$membership->member = [];
$membership->crseidnumber = $c->idnumber;
foreach ($users as $j => $u) {
if (isset($linkmatrix[$i][$j])) {
list($roletype, $rolestatus, $rolerecstatus) = explode(':', $linkmatrix[$i][$j]);
if (strlen($rolerecstatus) && strlen($roletype) && strlen($rolestatus)) {
$membership->member[] = (object)[
'useridnumber' => $u->idnumber,
'role' => [(object)[
'roletype' => $roletype,
'rolestatus' => $rolestatus,
'recstatus' => $rolerecstatus
]]
];
}
}
}
$memberships[] = $membership;
}
return $memberships;
}
/**
* Add new users, courses and enrolments
*/
public function test_users_are_enroled_on_courses() {
global $DB;
$prevnuserenrolments = $DB->count_records('user_enrolments');
$prevnusers = $DB->count_records('user');
$prevncourses = $DB->count_records('course');
$courses = $this->generate_test_course_records(1);
$users = $this->generate_test_user_records(1);
$coursemembership = $this->link_users_with_courses(
$users,
$courses,
[
['01:1:1'] // First course.
]
);
$this->set_xml_file($users, $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments'));
$this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
$this->assertEquals(($prevncourses + 1), $DB->count_records('course'));
}
/**
* Check that the unenrol actions are completely ignored when "unenrol" setting is disabled
*/
public function test_no_action_when_unenrol_disabled() {
global $DB;
$prevnuserenrolments = $DB->count_records('user_enrolments');
$prevnusers = $DB->count_records('user');
$prevncourses = $DB->count_records('course');
// Create user and course.
$courses = $this->generate_test_course_records(3);
$users = $this->generate_test_user_records(2);
$coursemembership = $this->link_users_with_courses(
$users,
$courses,
// Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA.
// Role statuses: 0=Inactive, 1=Active.
// Role recstatus: 1=Add, 2=Update, 3=Delete.
// Format of matrix elements: <roletype>:<role status>:<role recstatus>.
[
['01:1:1', '01:1:1'], // Course 1.
['01:1:1', '01:1:1'], // Course 2.
['::', '01:1:1'], // Course 3.
]
);
$this->set_xml_file($users, $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(($prevnuserenrolments + 5), $DB->count_records('user_enrolments'));
$this->assertEquals(($prevnusers + 2), $DB->count_records('user'));
$this->assertEquals(($prevncourses + 3), $DB->count_records('course'));
// Disallow unenrolment, and check that unenroling has no effect.
$this->imsplugin->set_config('imsunenrol', 0);
$coursemembership = $this->link_users_with_courses(
$users,
$courses,
// Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA.
// Role statuses: 0=Inactive, 1=Active.
// Role recstatus: 1=Add, 2=Update, 3=Delete.
// Format of matrix elements: <roletype>:<role status>:<role recstatus>.
[
['01:1:3', '01:1:3'], // Course 1.
['::', '01:1:3'], // Course 2.
['::', '01:1:3'], // Course 3.
]
);
$this->set_xml_file($users, $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(($prevnuserenrolments + 5), $DB->count_records('user_enrolments'));
$this->assertEquals(($prevnusers + 2), $DB->count_records('user'));
$this->assertEquals(($prevncourses + 3), $DB->count_records('course'));
}
/**
* When a user has existing roles and enrolments, they are unaffected by IMS instructions for other courses
*/
public function test_existing_roles_and_enrolments_unaffected() {
global $DB;
$this->imsplugin->set_config('imsunenrol', 1);
$this->imsplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL);
$prevnuserenrolments = $DB->count_records('user_enrolments');
$prevnusers = $DB->count_records('user');
$prevncourses = $DB->count_records('course');
$courses = $this->generate_test_course_records(2);
// Create_course seems to expect the category to be passed as ID, so extract from the object.
$course1 = $courses[0];
$course1->category = $course1->category->id;
$course1 = $this->getDataGenerator()->create_course($courses[0]);
// Enrol user1 on course1.
$DB->insert_record('enrol', (object)['enrol' => 'imsenterprise',
'courseid' => $course1->id, 'status' => 1, 'roleid' => 5
], true);
$user1 = $this->getDataGenerator()->create_and_enrol($course1, 'student',
['idnumber' => 'UserIDNumber100'], 'imsenterprise');
$user1->username = $user1->idnumber;
// Confirm user was added and that the enrolment happened.
$this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments'));
$this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
$this->assertEquals(($prevncourses + 1), $DB->count_records('course'));
// Capture DB id of enrolment record.
$initialusernerolment = $DB->get_record('user_enrolments', ['userid' => $user1->id],
'*', MUST_EXIST);
$initialroleassigned = $DB->get_record('role_assignments', ['userid' => $user1->id],
'*', MUST_EXIST);
// Add a new enrolment for the same user via IMS file.
$coursemembership = $this->link_users_with_courses(
[$user1],
$courses,
// Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA.
// Role statuses: 0=Inactive, 1=Active.
// Role recstatus: 1=Add, 2=Update, 3=Delete.
// Format of matrix elements: <roletype>:<role status>:<role recstatus>.
[
['::'], // Course 1.
['01:1:1'], // Course 2.
]
);
$this->set_xml_file([$user1], $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(2, $DB->count_records('user_enrolments', ['userid' => $user1->id]));
$this->assertEquals(($prevncourses + 2), $DB->count_records('course'));
// Unenrol the user from course2 via IMS file.
$coursemembership = $this->link_users_with_courses(
[$user1],
$courses,
// Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA.
// Role statuses: 0=Inactive, 1=Active.
// Role recstatus: 1=Add, 2=Update, 3=Delete.
// Format of matrix elements: <roletype>:<role status>:<role recstatus>.
[
['::'], // Course 1.
['01:0:3'], // Course 2.
]
);
$this->set_xml_file([$user1], $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(1, $DB->count_records('user_enrolments', ['userid' => $user1->id]));
$this->assertTrue($DB->record_exists('user_enrolments', ['id' => $initialusernerolment->id,
'userid' => $initialusernerolment->userid]));
$this->assertTrue($DB->record_exists('role_assignments', ['id' => $initialroleassigned->id,
'userid' => $initialusernerolment->userid]));
}
/**
* Enrolments alone are disabled
*/
public function test_disable_enrolments_only() {
global $DB;
$this->imsplugin->set_config('imsunenrol', 1);
$this->imsplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPEND);
$prevnuserenrolments = $DB->count_records('user_enrolments');
$prevnroles = $DB->count_records('role_assignments');
$prevnusers = $DB->count_records('user');
$prevncourses = $DB->count_records('course');
$courses = $this->generate_test_course_records(1);
$users = $this->generate_test_user_records(1);
// Add a new enrolment for the same user via IMS file.
$coursemembership = $this->link_users_with_courses(
$users,
$courses,
// Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA.
// Role statuses: 0=Inactive, 1=Active.
// Role recstatus: 1=Add, 2=Update, 3=Delete.
// Format of matrix elements: <roletype>:<role status>:<role recstatus>.
[
['01:1:1'], // Course 1.
]
);
$this->set_xml_file($users, $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(($prevncourses + 1), $DB->count_records('course'));
$this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
$this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments'));
$this->assertEquals(($prevnroles + 1), $DB->count_records('role_assignments'));
// Capture DB ids.
$dbuser = $DB->get_record('user', ['idnumber' => $users[0]->idnumber], '*', MUST_EXIST);
$dbenrolment = $DB->get_record('user_enrolments',
['userid' => $dbuser->id, 'status' => ENROL_USER_ACTIVE],
'*', MUST_EXIST
);
$dbrole = $DB->get_record('role_assignments', ['userid' => $dbuser->id], '*', MUST_EXIST);
// Unenrol the user, check that the enrolment and role exist, but the enrolment is suspended.
$coursemembership = $this->link_users_with_courses(
$users,
$courses,
// Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA.
// Role statuses: 0=Inactive, 1=Active.
// Role recstatus: 1=Add, 2=Update, 3=Delete.
// Format of matrix elements: <roletype>:<role status>:<role recstatus>.
[
['01:0:3'], // Course 1.
]
);
$this->set_xml_file($users, $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(($prevncourses + 1), $DB->count_records('course'));
$this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
$this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments'));
$this->assertEquals(($prevnroles + 1), $DB->count_records('role_assignments'));
$this->assertEquals(1, $DB->count_records('user_enrolments',
['userid' => $dbuser->id, 'id' => $dbenrolment->id, 'status' => ENROL_USER_SUSPENDED]));
$this->assertEquals(1, $DB->count_records('role_assignments',
['userid' => $dbuser->id, 'id' => $dbrole->id]));
}
/**
* Enrolments are disabled but retained) and roles removed
*/
public function test_disable_enrolments_and_remove_roles() {
global $DB;
$this->imsplugin->set_config('imsunenrol', 1);
$this->imsplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
$prevnuserenrolments = $DB->count_records('user_enrolments');
$prevnroles = $DB->count_records('role_assignments');
$prevnusers = $DB->count_records('user');
$prevncourses = $DB->count_records('course');
$courses = $this->generate_test_course_records(1);
$users = $this->generate_test_user_records(1);
// Add a new enrolment for the same user via IMS file.
$coursemembership = $this->link_users_with_courses(
$users,
$courses,
// Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA.
// Role statuses: 0=Inactive, 1=Active.
// Role recstatus: 1=Add, 2=Update, 3=Delete.
// Format of matrix elements: <roletype>:<role status>:<role recstatus>.
[
['01:1:1'], // Course 1.
]
);
$this->set_xml_file($users, $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(($prevncourses + 1), $DB->count_records('course'));
$this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
$this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments'));
$this->assertEquals(($prevnroles + 1), $DB->count_records('role_assignments'));
// Capture DB ids.
$dbuser = $DB->get_record('user', ['idnumber' => $users[0]->idnumber], '*', MUST_EXIST);
$dbenrolment = $DB->get_record('user_enrolments',
['userid' => $dbuser->id, 'status' => ENROL_USER_ACTIVE],
'*', MUST_EXIST
);
$dbrole = $DB->get_record('role_assignments', ['userid' => $dbuser->id], '*', MUST_EXIST);
// Unenrol the user, check that the enrolment and role exist, but the enrolment is suspended.
$coursemembership = $this->link_users_with_courses(
$users,
$courses,
// Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA.
// Role statuses: 0=Inactive, 1=Active.
// Role recstatus: 1=Add, 2=Update, 3=Delete.
// Format of matrix elements: <roletype>:<role status>:<role recstatus>.
[
['01:0:3'], // Course 1.
]
);
$this->set_xml_file($users, $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(($prevncourses + 1), $DB->count_records('course'));
$this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
$this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments'));
$this->assertEquals(($prevnroles), $DB->count_records('role_assignments'));
$this->assertEquals(1, $DB->count_records('user_enrolments',
['userid' => $dbuser->id, 'id' => $dbenrolment->id, 'status' => ENROL_USER_SUSPENDED]));
$this->assertEquals(0, $DB->count_records('role_assignments',
['userid' => $dbuser->id, 'id' => $dbrole->id]));
}
/**
* Enrolments and roles are deleted for specified user
*/
public function test_delete_roles_and_enrolments() {
global $DB;
$this->imsplugin->set_config('imsunenrol', 1);
$this->imsplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL);
$prevnuserenrolments = $DB->count_records('user_enrolments');
$prevnroles = $DB->count_records('role_assignments');
$prevnusers = $DB->count_records('user');
$prevncourses = $DB->count_records('course');
$courses = $this->generate_test_course_records(1);
$users = $this->generate_test_user_records(1);
// Add a new enrolment for the same user via IMS file.
$coursemembership = $this->link_users_with_courses(
$users,
$courses,
// Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA.
// Role statuses: 0=Inactive, 1=Active.
// Role recstatus: 1=Add, 2=Update, 3=Delete.
// Format of matrix elements: <roletype>:<role status>:<role recstatus>.
[
['01:1:1'], // Course 1.
]
);
$this->set_xml_file($users, $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(($prevncourses + 1), $DB->count_records('course'));
$this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
$this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments'));
$this->assertEquals(($prevnroles + 1), $DB->count_records('role_assignments'));
// Capture DB ids.
$dbuser = $DB->get_record('user', ['idnumber' => $users[0]->idnumber], '*', MUST_EXIST);
$dbenrolment = $DB->get_record('user_enrolments',
['userid' => $dbuser->id, 'status' => ENROL_USER_ACTIVE],
'*', MUST_EXIST
);
$dbrole = $DB->get_record('role_assignments', ['userid' => $dbuser->id], '*', MUST_EXIST);
// Unenrol the user, check that the enrolment and role exist, but the enrolment is suspended.
$coursemembership = $this->link_users_with_courses(
$users,
$courses,
// Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA.
// Role statuses: 0=Inactive, 1=Active.
// Role recstatus: 1=Add, 2=Update, 3=Delete.
// Format of matrix elements: <roletype>:<role status>:<role recstatus>.
[
['01:1:3'], // Course 1.
]
);
$this->set_xml_file($users, $courses, $coursemembership);
$this->imsplugin->cron();
$this->assertEquals(($prevncourses + 1), $DB->count_records('course'));
$this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
$this->assertEquals(($prevnuserenrolments), $DB->count_records('user_enrolments'));
$this->assertEquals(($prevnroles), $DB->count_records('role_assignments'));
$this->assertEquals(0, $DB->count_records('user_enrolments',
['userid' => $dbuser->id, 'id' => $dbenrolment->id, 'status' => ENROL_USER_SUSPENDED]));
$this->assertEquals(0, $DB->count_records('role_assignments',
['userid' => $dbuser->id, 'id' => $dbrole->id]));
}
}