allow_allcourses: expose all courses to external enrolment // $config->allowed_categories: serialised array of courses allowed // $config->allowed_courses: serialised array of courses allowed class enrolment_plugin_mnet { /// Override the base config_form() function function config_form($frm) { global $CFG; $vars = array('enrol_mnet_allow_allcourses', 'enrol_mnet_allowed_categories', 'enrol_mnet_allowed_courses'); foreach ($vars as $var) { if (!isset($frm->$var)) { $frm->$var = ''; } } $mnethosts = $this->list_remote_servers(); include ("$CFG->dirroot/enrol/mnet/config.html"); } /// Override the base process_config() function function process_config($config) { if (!isset($config->enrol_mnet_allow_allcourses)) { $config->enrol_mnet_allow_allcourses = false; } set_config('enrol_mnet_allow_allcourses', $config->enrol_mnet_allow_allcourses); if (!isset($config->enrol_mnet_allowed_categories)) { $config->enrol_mnet_allowed_categories = ''; } set_config('enrol_mnet_allowed_categories', $config->enrol_mnet_allowed_categories); if (!isset($config->enrol_mnet_allowed_courses)) { $config->enrol_mnet_allowed_courses = ''; } set_config('enrol_mnet_allowed_courses', $config->enrol_mnet_allowed_courses); return true; } /// Override the get_access_icons() function function get_access_icons($course) { } /** * Override the base cron() function */ //function cron() { // //} // end of cron() /*** *** MNET functions *** ***/ function mnet_publishes() { $enrol = array(); $enrol['name'] = 'mnet_enrol'; // Name & Description go in lang file $enrol['apiversion'] = 1; $enrol['methods'] = array('available_courses','user_enrolments', 'enrol_user', 'unenrol_user', 'course_enrolments' ); return array($enrol); } /** * Does Foo * * @param string $username The username * @param int $mnethostid The id of the remote mnethost * @return bool Whether the user can login from the remote host */ function available_courses() { global $CFG; if (!empty($CFG->enrol_mnet_allow_allcourses)) { $query = "SELECT co.id AS remoteid, ca.id AS cat_id, ca.name AS cat_name, ca.description AS cat_description, co.sortorder, co.fullname, co.shortname, co.idnumber, co.summary, co.startdate, co.cost, co.currency, co.defaultrole AS defaultroleid, r.name AS defaultrolename FROM {$CFG->prefix}course_categories ca JOIN {$CFG->prefix}course co ON ca.id = co.category LEFT JOIN {$CFG->prefix}role r ON r.id = co.defaultrole WHERE co.visible = '1' AND co.enrollable = '1' ORDER BY sortorder ASC "; return get_records_sql($query); } elseif (!empty($CFG->enrol_mnet_allowed_categories)) { $cats = preg_split('/\s*,\s*/', $CFG->enrol_mnet_allowed_categories); for ($n=0;$n < count($cats); $n++) { $cats[$n] = " ca.path LIKE '%/" . (int)$cats[$n] . "/%' "; } $cats = join(' OR ', $cats); $query = "SELECT id, name FROM {$CFG->prefix}course_categories ca WHERE ca.id IN ({$CFG->enrol_mnet_allowed_categories}) OR ( $cats ) ORDER BY path ASC, depth ASC "; unset($cats); $rs = get_records_sql($query); if (!empty($rs)) { $cats = array_keys($rs); } $where = ' AND ( ca.id IN (' . join(',', $cats) . ') '; if (!empty($CFG->enrol_mnet_allowed_courses)) { $where .= " OR co.id in ({$CFG->enrol_mnet_allowed_courses}) "; } $where .= ')'; $query = "SELECT co.id as remoteid, ca.id as cat_id, ca.name as cat_name, ca.description as cat_description, co.sortorder, co.fullname, co.shortname, co.idnumber, co.summary, co.startdate, co.cost, co.currency, co.defaultrole as defaultroleid, r.name FROM {$CFG->prefix}course_categories ca JOIN {$CFG->prefix}course co ON ca.id = co.category LEFT JOIN {$CFG->prefix}role r ON r.id = co.defaultrole WHERE co.visible = '1' AND co.enrollable = '1' $where ORDER BY sortorder ASC "; return get_records_sql($query); } elseif (!empty($CFG->enrol_mnet_allowed_courses)) { $query = "SELECT co.id as remoteid, ca.id as cat_id, ca.name as cat_name, ca.description as cat_description, co.sortorder, co.fullname, co.shortname, co.idnumber, co.summary, co.startdate, co.cost, co.currency, co.defaultrole as defaultroleid, r.name FROM {$CFG->prefix}course_categories ca JOIN {$CFG->prefix}course co ON ca.id = co.category LEFT JOIN {$CFG->prefix}role r ON r.id = co.defaultrole WHERE co.visible = '1' AND co.enrollable = '1' AND co.id in ({$CFG->enrol_mnet_allowed_courses}) ORDER BY sortorder ASC "; return get_records_sql($query); } return array(); } /** * */ function user_enrolments($userid) { return array(); } /** * Get a list of users from the client server who are enrolled in a course * * @param int $courseid The Course ID * @param string $roles Comma-separated list of role shortnames * @return array Array of usernames who are homed on the * client machine */ function course_enrolments($courseid, $roles = '') { global $MNET_REMOTE_CLIENT, $CFG; if (! $course = get_record('course', 'id', $courseid) ) { return 'no course'; //error("That's an invalid course id"); } $context = get_context_instance(CONTEXT_COURSE, $courseid); $sql = " SELECT u.id, u.username, a.enrol, a.timemodified, r.name, r.shortname FROM {$CFG->prefix}role_assignments a, {$CFG->prefix}role r, {$CFG->prefix}user u WHERE a.contextid = '{$context->id}' AND a.roleid = r.id AND a.userid = u.id AND u.mnethostid = '{$MNET_REMOTE_CLIENT->id}' "; if(!empty($roles)) { // $default_role = get_default_course_role($course); ??? $sql .= " AND a.roleid in ('".str_replace(',', "', '", $roles)."')"; } $enrolments = get_records_sql($sql); $returnarray = array(); foreach($enrolments as $user) { $returnarray[$user->username] = array('enrol' => $user->enrol, 'timemodified' => $user->timemodified, 'shortname' => $user->shortname, 'username' => $user->username, 'name' => $user->name); } return $returnarray; } /** * Enrols user to course with the default role * * @param string $username The username of the remote use * @param int $courseid The id of the local course * @return bool Whether the enrolment has been successful */ function enrol_user($user, $courseid) { global $MNET, $MNET_REMOTE_CLIENT; $userrecord = get_record('user','username',addslashes($user['username']), 'mnethostid',$MNET_REMOTE_CLIENT->id); if ($userrecord == false) { // We should at least be checking that we allow the remote // site to create users // TODO: more rigour here thanks! $userrecord = new stdClass(); $userrecord->username = addslashes($user['username']); $userrecord->email = addslashes($user['email']); $userrecord->firstname = addslashes($user['firstname']); $userrecord->lastname = addslashes($user['lastname']); $userrecord->mnethostid = $MNET_REMOTE_CLIENT->id; if ($userrecord->id = insert_record('user', $userrecord)) { $userrecord = get_record('user','id', $userrecord->id); } else { // TODO: Error out return false; } } if (! $course = get_record('course', 'id', $courseid) ) { // TODO: Error out return false; } $courses = $this->available_courses(); if (!empty($courses[$courseid])) { if (enrol_into_course($course, $userrecord, 'mnet')) { return true; } } return false; } /** * Unenrol a user from a course * * @param string $username The username * @param int $courseid The id of the local course * @return bool Whether the user can login from the remote host */ function unenrol_user($username, $courseid) { global $MNET_REMOTE_CLIENT; $userrecord = get_record('user', 'username', addslashes($username), 'mnethostid', $MNET_REMOTE_CLIENT->id); if ($userrecord == false) { return false; // TODO: Error out } if (! $course = get_record('course', 'id', $courseid) ) { return false; // TODO: Error out } if (! $context = get_context_instance(CONTEXT_COURSE, $course->id)) { return false; // TODO: Error out (Invalid context) } // Are we a *real* user or the shady MNET Daemon? // require_capability('moodle/role:assign', $context, NULL, false); if (!role_unassign(0, $userrecord->id, 0, $context->id)) { error("An error occurred while trying to unenrol that person."); } return true; } /*** *** Client RPC behaviour *** *** ***/ /** * Lists remote servers we use 'enrol' services from. * * @return array */ function list_remote_servers() { global $CFG; $sql = " SELECT DISTINCT h.id, h.name FROM {$CFG->prefix}mnet_host h, {$CFG->prefix}mnet_host2service h2s, {$CFG->prefix}mnet_service s WHERE h.id = h2s.hostid AND h2s.serviceid = s.id AND s.name = 'mnet_enrol' AND h2s.subscribe = 1"; $res = get_records_sql($sql); if (is_array($res)) { return $res; } else { return array(); } } /** * Does Foo * * @param int $mnethostid The id of the remote mnethost * @return array Whether the user can login from the remote host */ function fetch_remote_courses($mnethostid) { global $CFG; global $USER; global $MNET; require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; // get the Service Provider info $mnet_sp = new mnet_peer(); $mnet_sp->set_id($mnethostid); // set up the RPC request $mnetrequest = new mnet_xmlrpc_client(); $mnetrequest->set_method('enrol/mnet/enrol.php/available_courses'); // Initialise $message $message = ''; // TODO: cache for a while (10 minutes?) // Thunderbirds are go! Do RPC call and store response if ($mnetrequest->send($mnet_sp) === true) { $courses = $mnetrequest->response; // get the cached courses key'd on remote id - only need remoteid and id fields $cachedcourses = get_records('mnet_enrol_course', 'hostid', $mnethostid, 'remoteid', 'remoteid, id' ); // Update cache and transform $courses into objects // in-place for the benefit of our caller... for ($n=0;$nremoteid = (int)$course->remoteid; $course->hostid = $mnethostid; $course->cat_id = (int)$course->cat_id; $course->sortorder = (int)$course->sortorder ; $course->startdate = (int)$course->startdate; $course->cost = (int)$course->cost; $course->defaultroleid = (int)$course->defaultroleid; // sanitise strings for DB NOTE - these are not sane // for printing, so we'll use a different object $dbcourse = clone($course); $dbcourse->cat_name = addslashes(substr($dbcourse->cat_name,0,255)); $dbcourse->cat_description = addslashes($dbcourse->cat_description); $dbcourse->fullname = addslashes(substr($dbcourse->fullname,0,254)); $dbcourse->shortname = addslashes(substr($dbcourse->shortname,0,15)); $dbcourse->idnumber = addslashes(substr($dbcourse->idnumber,0,100)); $dbcourse->summary = addslashes($dbcourse->summary); $dbcourse->currency = addslashes(substr($dbcourse->currency,0,3)); $dbcourse->defaultrolename = addslashes(substr($dbcourse->defaultrolename,0,255)); // insert or update if (empty($cachedcourses[$course->remoteid])) { $course->id = insert_record('mnet_enrol_course', $dbcourse); } else { $course->id = $cachedcourses[$course->remoteid]->id; $cachedcourses[$course->remoteid]->seen=true; update_record('mnet_enrol_course', $dbcourse); } // free tmp obj unset($dbcourse); } // prune stale data from cache if (!empty($cachedcourses)) { $stale = array(); foreach ($cachedcourses as $id => $cc) { // TODO: maybe set a deleted flag instead if (empty($cc->seen)) { $stale[] = $cc->id; } } if (!empty($stale)) { delete_records_select('mnet_enrol_course', 'id IN ('.join(',',$stale).')'); } } return $courses; } else { foreach ($mnetrequest->error as $errormessage) { list($code, $errormessage) = array_map('trim',explode(':', $errormessage, 2)); $message .= "ERROR $code:
$errormessage
"; } error("RPC enrol/mnet/available_courses:
$message"); } return false; } /** * Does Foo * * @param int $mnethostid The id of the remote mnethost * @return array Whether the user can login from the remote host */ function req_enrol_user($userid, $courseid) { global $CFG; global $USER; global $MNET; require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; // Prepare a basic user record // in case the remote host doesn't have it $user = get_record('user', 'id', $userid, '','','','', 'username, email, firstname, lastname'); $user = (array)$user; $course = get_record('mnet_enrol_course', 'id', $courseid); // get the Service Provider info $mnet_sp = new mnet_peer(); $mnet_sp->set_id($course->hostid); // set up the RPC request $mnetrequest = new mnet_xmlrpc_client(); $mnetrequest->set_method('enrol/mnet/enrol.php/enrol_user'); $mnetrequest->add_param($user); $mnetrequest->add_param($course->remoteid); // Thunderbirds are go! Do RPC call and store response if ($mnetrequest->send($mnet_sp) === true) { if ($mnetrequest->response == true) { // now store it in the mnet_enrol_assignments table $assignment = new StdClass; $assignment->userid = $userid; $assignment->hostid = $course->hostid; $assignment->courseid = $course->id; $assignment->enroltype = 'mnet'; // TODO: other fields if (insert_record('mnet_enrol_assignments', $assignment)) { return true; } } } return false; } /** * Does Foo * * @param int $mnethostid The id of the remote mnethost * @return array Whether the user can login from the remote host */ function req_unenrol_user($userid, $courseid) { global $CFG; global $USER; global $MNET; require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; // in case the remote host doesn't have it $username = get_field('user', 'username', 'id', $userid); $course = get_record('mnet_enrol_course', 'id', $courseid); // get the Service Provider info $mnet_sp = new mnet_peer(); $mnet_sp->set_id($course->hostid); // set up the RPC request $mnetrequest = new mnet_xmlrpc_client(); $mnetrequest->set_method('enrol/mnet/enrol.php/unenrol_user'); $mnetrequest->add_param($username); $mnetrequest->add_param($course->remoteid); // TODO - prevent removal of enrolments that are not of // type mnet... // Thunderbirds are go! Do RPC call and store response if ($mnetrequest->send($mnet_sp) === true) { if ($mnetrequest->response == true) { // remove enrolment cached in mnet_enrol_assignments delete_records_select('mnet_enrol_assignments', "userid={$userid} AND courseid={$course->id}"); return true; } } return false; } } // end of class ?>