first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,221 @@
<?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/>.
/**
* Privacy Subsystem implementation for mnetservice_enrol.
*
* @package mnetservice_enrol
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mnetservice_enrol\privacy;
defined('MOODLE_INTERNAL') || die();
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\context;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
use core_privacy\local\request\userlist;
use core_privacy\local\request\approved_userlist;
/**
* Privacy Subsystem for mnetservice_enrol implementing metadata and plugin providers.
*
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\core_userlist_provider,
\core_privacy\local\request\plugin\provider {
/**
* Returns meta data about this system.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection): collection {
$collection->add_database_table(
'mnetservice_enrol_enrolments',
[
'hostid' => 'privacy:metadata:mnetservice_enrol_enrolments:hostid',
'userid' => 'privacy:metadata:mnetservice_enrol_enrolments:userid',
'remotecourseid' => 'privacy:metadata:mnetservice_enrol_enrolments:remotecourseid',
'rolename' => 'privacy:metadata:mnetservice_enrol_enrolments:rolename',
'enroltime' => 'privacy:metadata:mnetservice_enrol_enrolments:enroltime',
'enroltype' => 'privacy:metadata:mnetservice_enrol_enrolments:enroltype'
],
'privacy:metadata:mnetservice_enrol_enrolments:tableexplanation'
);
return $collection;
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid): contextlist {
$sql = "SELECT c.id
FROM {context} c
JOIN {mnetservice_enrol_enrolments} me
ON me.userid = c.instanceid
AND c.contextlevel = :contextlevel
WHERE me.userid = :userid";
$params = [
'contextlevel' => CONTEXT_USER,
'userid' => $userid
];
$contextlist = new contextlist();
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Get the list of users within a specific context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*/
public static function get_users_in_context(userlist $userlist) {
$context = $userlist->get_context();
if (!$context instanceof \context_user) {
return;
}
$params = ['userid' => $context->instanceid];
$sql = "SELECT userid
FROM {mnetservice_enrol_enrolments}
WHERE userid = :userid";
$userlist->add_from_sql('userid', $sql, $params);
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;
if (empty($contextlist->count())) {
return;
}
$userid = $contextlist->get_user()->id;
$contextuser = \context_user::instance($userid);
list($insql, $inparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
$params = [
'userid' => $userid,
'contextlevel' => CONTEXT_USER
];
$params += $inparams;
$sql = "SELECT me.id,
me.rolename,
me.enroltime,
me.enroltype,
mh.name as hostname,
mc.fullname
FROM {mnetservice_enrol_enrolments} me
JOIN {context} ctx
ON ctx.instanceid = me.userid
AND ctx.contextlevel = :contextlevel
JOIN {mnet_host} mh
ON mh.id = me.hostid
JOIN {mnetservice_enrol_courses} mc
ON mc.remoteid = me.remotecourseid
WHERE me.userid = :userid
AND ctx.id {$insql}";
$mnetenrolments = $DB->get_records_sql($sql, $params);
foreach ($mnetenrolments as $mnetenrolment) {
// The core_enrol data export is organised in:
// {User Context}/User enrolments/data.json.
$data[] = (object) [
'host' => $mnetenrolment->hostname,
'remotecourseid' => $mnetenrolment->fullname,
'rolename' => $mnetenrolment->rolename,
'enroltime' => transform::datetime($mnetenrolment->enroltime),
'enroltype' => $mnetenrolment->enroltype
];
}
writer::with_context($contextuser)->export_data(
[get_string('privacy:metadata:mnetservice_enrol_enrolments', 'mnetservice_enrol')],
(object)$data
);
}
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
// Sanity check that context is at the User context level.
if ($context->contextlevel == CONTEXT_USER) {
static::delete_user_data($context->instanceid);
}
}
/**
* Delete multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist) {
$context = $userlist->get_context();
if ($context instanceof \context_user) {
static::delete_user_data($context->instanceid);
}
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
if (empty($contextlist->count())) {
return;
}
$user = $contextlist->get_user();
foreach ($contextlist->get_contexts() as $context) {
// Verify the context is a user context and that the instanceid matches the userid of the contextlist.
if ($context->contextlevel == CONTEXT_USER && $context->instanceid == $user->id) {
// Get the data and write it.
static::delete_user_data($user->id);
}
}
}
/**
* This does the deletion of user data for the mnetservice_enrolments.
*
* @param int $userid The user ID
*/
protected static function delete_user_data(int $userid) {
global $DB;
// Because we only use user contexts the instance ID is the user ID.
$DB->delete_records('mnetservice_enrol_enrolments', ['userid' => $userid]);
}
}
+200
View File
@@ -0,0 +1,200 @@
<?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/>.
/**
* Page to enrol our users into remote courses
*
* @package plugintype
* @subpackage pluginname
* @copyright 2010 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require(__DIR__.'/../../../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->dirroot.'/mnet/service/enrol/locallib.php');
require_sesskey();
$hostid = required_param('host', PARAM_INT); // remote host id in our mnet_host table
$courseid = required_param('course', PARAM_INT); // id of the course in our cache table
$usecache = optional_param('usecache', true, PARAM_BOOL); // use cached list of enrolments
admin_externalpage_setup('mnetenrol', '', array('host'=>$hostid, 'course'=>$courseid, 'usecache'=>1, 'sesskey'=>sesskey()),
new moodle_url('/mnet/service/enrol/course.php'));
$service = mnetservice_enrol::get_instance();
if (!$service->is_available()) {
echo $OUTPUT->box(get_string('mnetdisabled','mnet'), 'noticebox');
echo $OUTPUT->footer();
die();
}
// remote hosts that may publish remote enrolment service and we are subscribed to it
$hosts = $service->get_remote_publishers();
if (empty($hosts[$hostid])) {
throw new \moodle_exception('wearenotsubscribedtothishost', 'mnetservice_enrol');
}
$host = $hosts[$hostid];
$course = $DB->get_record('mnetservice_enrol_courses', array('id'=>$courseid, 'hostid'=>$host->id), '*', MUST_EXIST);
echo $OUTPUT->header();
// course name
$icon = $OUTPUT->pix_icon('i/course', get_string('category'));
echo $OUTPUT->heading($icon . s($course->fullname));
// collapsible course summary
if (!empty($course->summary)) {
$options = new stdClass();
$options->trusted = false;
$options->para = false;
$options->filter = false;
$options->noclean = false;
$options->overflowdiv = true;
print_collapsible_region_start('remotecourse summary', 'remotecourse-summary', get_string('coursesummary'), false, true);
echo format_text($course->summary, $course->summaryformat, $options);
print_collapsible_region_end();
}
$error = '';
$lastfetchenrolments = get_config('mnetservice_enrol', 'lastfetchenrolments');
if (!$usecache or empty($lastfetchenrolments) or (time()-$lastfetchenrolments > 600)) {
// fetch fresh data from remote if we just came from the course selection screen
// or every 10 minutes
$usecache = false;
$result = $service->req_course_enrolments($host->id, $course->remoteid, $usecache);
if ($result !== true) {
$error .= $service->format_error_message($result);
}
}
// user selectors
$currentuserselector = new mnetservice_enrol_existing_users_selector('removeselect', array('hostid'=>$host->id, 'remotecourseid'=>$course->remoteid));
$potentialuserselector = new mnetservice_enrol_potential_users_selector('addselect', array('hostid'=>$host->id, 'remotecourseid'=>$course->remoteid));
// process incoming enrol request
if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) {
$userstoassign = $potentialuserselector->get_selected_users();
if (!empty($userstoassign)) {
foreach($userstoassign as $adduser) {
$user = $DB->get_record('user', array('id'=>$adduser->id));
$result = $service->req_enrol_user($user, $course);
if ($result !== true) {
$error .= $service->format_error_message($result);
}
}
$potentialuserselector->invalidate_selected_users();
$currentuserselector->invalidate_selected_users();
}
}
// process incoming unenrol request
if (optional_param('remove', false, PARAM_BOOL) && confirm_sesskey()) {
$userstounassign = $currentuserselector->get_selected_users();
if (!empty($userstounassign)) {
foreach($userstounassign as $removeuser) {
$user = $DB->get_record('user', array('id'=>$removeuser->id));
$result = $service->req_unenrol_user($user, $course);
if ($result !== true) {
$error .= $service->format_error_message($result);
}
}
$potentialuserselector->invalidate_selected_users();
$currentuserselector->invalidate_selected_users();
}
}
if (!empty($error)) {
echo $OUTPUT->box($error, 'generalbox error');
}
// print form to enrol our students
?>
<form id="assignform" method="post" action="<?php echo $PAGE->url ?>">
<div>
<input type="hidden" name="sesskey" value="<?php echo sesskey() ?>" />
<input type="hidden" name="hostid" value="<?php echo $host->id ?>" />
<input type="hidden" name="courseid" value="<?php echo $course->id ?>" />
<table summary="" class="roleassigntable generaltable generalbox boxaligncenter" cellspacing="0">
<tr>
<td id="existingcell">
<p><label for="removeselect"><?php print_string('enrolledusers', 'enrol'); ?></label></p>
<?php $currentuserselector->display() ?>
</td>
<td id="buttonscell">
<div id="addcontrols">
<input name="add" id="add" type="submit" value="<?php echo $OUTPUT->larrow().'&nbsp;'.get_string('add'); ?>" title="<?php print_string('add'); ?>" /><br />
<div class="enroloptions">
<p><?php echo get_string('assignrole', 'role') .': '. s($course->rolename); ?></p>
</div>
</div>
<div id="removecontrols">
<input name="remove" id="remove" type="submit" value="<?php echo get_string('remove').'&nbsp;'.$OUTPUT->rarrow(); ?>" title="<?php print_string('remove'); ?>" />
</div>
</td>
<td id="potentialcell">
<p><label for="addselect"><?php print_string('enrolcandidates', 'enrol'); ?></label></p>
<?php $potentialuserselector->display() ?>
</td>
</tr>
</table>
</div>
</form>
<?php
// eventually display other enrolments of our users (manual, self etc.) in the remote course
list($sort, $params) = users_order_by_sql('u');
$sql = "SELECT e.id,e.enroltype AS plugin, u.firstname, u.lastname, u.email, u.id AS userid,
e.enroltime AS timemodified, e.rolename
FROM {mnetservice_enrol_enrolments} e
JOIN {user} u ON u.id = e.userid
WHERE e.hostid = :hostid AND e.remotecourseid = :remotecourseid AND e.enroltype != 'mnet'
ORDER BY $sort";
$params['hostid'] = $host->id;
$params['remotecourseid'] = $course->remoteid;
if ($enrolments = $DB->get_records_sql($sql, $params)) {
echo $OUTPUT->heading(get_string('otherenrolledusers', 'mnetservice_enrol'), 3);
$table = new html_table();
$table->attributes['class'] = 'generaltable otherenrolledusers';
$table->head = array(get_string('fullnameuser'), get_string('role'), get_string('plugin'));
foreach ($enrolments as $enrolleduser) {
$table->data[] = array(fullname($enrolleduser), s($enrolleduser->rolename), s($enrolleduser->plugin));
}
echo html_writer::table($table);
}
if ($usecache) {
echo $OUTPUT->single_button(new moodle_url($PAGE->url, array('usecache'=>0, 'sesskey'=>sesskey())),
get_string('refetch', 'mnetservice_enrol'), 'get');
}
echo $OUTPUT->single_button(new moodle_url('/mnet/service/enrol/host.php', array('id'=>$host->id)),
get_string('availablecourseson', 'mnetservice_enrol', s($host->hostname)), 'get');
echo $OUTPUT->footer();
+48
View File
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mnet/service/enrol/db" VERSION="20120122" COMMENT="XMLDB file for MNet service plugin mnet/service/enrol"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="mnetservice_enrol_courses" COMMENT="Caches the information fetched via XML-RPC about courses on remote hosts that are offered for our users">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" COMMENT="Unique remote-course ID"/>
<FIELD NAME="hostid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The id of the remote MNet host"/>
<FIELD NAME="remoteid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="ID of course on its home server"/>
<FIELD NAME="categoryid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The id of the category on the remote server"/>
<FIELD NAME="categoryname" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="fullname" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="shortname" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="idnumber" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="summary" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="summaryformat" TYPE="int" LENGTH="3" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="Format of the summary field"/>
<FIELD NAME="startdate" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="roleid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The ID of the role at the remote server that our users will get when we enrol them there"/>
<FIELD NAME="rolename" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The name of the role at the remote server that our users will get when we enrol them there"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="primary key of the mnet_course table"/>
</KEYS>
<INDEXES>
<INDEX NAME="uq_hostid_remoteid" UNIQUE="true" FIELDS="hostid, remoteid" COMMENT="The id of the course on its host must be unique"/>
</INDEXES>
</TABLE>
<TABLE NAME="mnetservice_enrol_enrolments" COMMENT="Caches the information about enrolments of our local users in courses on remote hosts">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" COMMENT="Unique enrollment ID"/>
<FIELD NAME="hostid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="ID of the remote MNet host"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="ID of our local user on this server"/>
<FIELD NAME="remotecourseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="ID of the course at the remote server. Note that this may and may not be cached in our mnetservice_enrol_courses table, depends of whether the course is opened for remote enrolments or our student is the enrolled there via other plugin"/>
<FIELD NAME="rolename" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="enroltime" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="enroltype" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" COMMENT="The name of the enrol plugin at the remote server that was used to enrol our student into their course"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="primary key"/>
<KEY NAME="fk_user" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id"/>
<KEY NAME="fk_mnet_host" TYPE="foreign" FIELDS="hostid" REFTABLE="mnet_host" REFFIELDS="id"/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>
+119
View File
@@ -0,0 +1,119 @@
<?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/>.
/**
* Displays a list of remote courses offered by a given host for our students
*
* By default the courses information is cached in our local DB table. Parameter
* $usecache can be used to force re-fetching up to date state from remote
* hosts (session key required in such case).
*
* @package mnetservice
* @subpackage enrol
* @copyright 2010 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require(__DIR__.'/../../../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->dirroot.'/mnet/service/enrol/locallib.php');
$hostid = required_param('id', PARAM_INT); // remote host id
$usecache = optional_param('usecache', true, PARAM_BOOL); // use cached list of courses
admin_externalpage_setup('mnetenrol', '', array('id'=>$hostid, 'usecache'=>1),
new moodle_url('/mnet/service/enrol/host.php'));
$service = mnetservice_enrol::get_instance();
if (!$service->is_available()) {
echo $OUTPUT->box(get_string('mnetdisabled','mnet'), 'noticebox');
echo $OUTPUT->footer();
die();
}
// remote hosts that may publish remote enrolment service and we are subscribed to it
$hosts = $service->get_remote_publishers();
if (empty($hosts[$hostid])) {
throw new \moodle_exception('wearenotsubscribedtothishost', 'mnetservice_enrol');
}
$host = $hosts[$hostid];
if (!$usecache) {
// our local database will be changed
require_sesskey();
}
$courses = $service->get_remote_courses($host->id, $usecache);
if (is_string($courses)) {
throw new \moodle_exception('fetchingcourses', 'mnetservice_enrol', '', null, $service->format_error_message($courses));
}
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('availablecourseson', 'mnetservice_enrol', s($host->hostname)));
if (empty($courses)) {
$a = (object)array('hostname' => s($host->hostname), 'hosturl' => s($host->hosturl));
echo $OUTPUT->box(get_string('availablecoursesonnone','mnetservice_enrol', $a), 'noticebox');
if ($usecache) {
echo $OUTPUT->single_button(new moodle_url($PAGE->url, array('usecache'=>0, 'sesskey'=>sesskey())),
get_string('refetch', 'mnetservice_enrol'), 'get');
}
echo $OUTPUT->footer();
die();
}
$table = new html_table();
$table->head = array(
get_string('shortnamecourse'),
get_string('fullnamecourse'),
get_string('role'),
get_string('action')
);
$table->attributes['class'] = 'generaltable remotecourses';
$icon = $OUTPUT->pix_icon('i/course', get_string('category'));
$prevcat = null;
foreach ($courses as $course) {
$course = (object)$course;
if ($prevcat !== $course->categoryid) {
$row = new html_table_row();
$cell = new html_table_cell($icon . s($course->categoryname));
$cell->header = true;
$cell->attributes['class'] = 'categoryname';
$cell->colspan = 4;
$row->cells = array($cell);
$table->data[] = $row;
$prevcat = $course->categoryid;
}
$editbtn = $OUTPUT->single_button(new moodle_url('/mnet/service/enrol/course.php',
array('host'=>$host->id, 'course'=>$course->id, 'usecache'=>0, 'sesskey'=>sesskey())),
get_string('editenrolments', 'mnetservice_enrol'), 'get');
$row = new html_table_row();
$row->cells = array(
s($course->shortname),
s($course->fullname),
s($course->rolename),
$editbtn
);
$table->data[] = $row;
}
echo html_writer::table($table);
if ($usecache) {
echo $OUTPUT->single_button(new moodle_url($PAGE->url, array('usecache'=>0, 'sesskey'=>sesskey())),
get_string('refetch', 'mnetservice_enrol'), 'get');
}
echo $OUTPUT->footer();
+76
View File
@@ -0,0 +1,76 @@
<?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/>.
/**
* Displays the list of remote peers we can enrol our users to
*
* @package mnetservice
* @subpackage enrol
* @copyright 2010 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require(__DIR__.'/../../../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->dirroot.'/mnet/service/enrol/locallib.php');
admin_externalpage_setup('mnetenrol');
$service = mnetservice_enrol::get_instance();
echo $OUTPUT->header();
echo $OUTPUT->heading_with_help(get_string('clientname', 'mnetservice_enrol'), 'clientname', 'mnetservice_enrol');
if (!$service->is_available()) {
echo $OUTPUT->box(get_string('mnetdisabled','mnet'), 'noticebox');
echo $OUTPUT->footer();
die();
}
$roamingusers = get_users_by_capability(context_system::instance(), 'moodle/site:mnetlogintoremote', 'u.id');
if (empty($roamingusers)) {
$capname = get_string('site:mnetlogintoremote', 'role');
$url = new moodle_url('/admin/roles/manage.php');
echo notice(get_string('noroamingusers', 'mnetservice_enrol', $capname), $url);
}
unset($roamingusers);
// remote hosts that may publish remote enrolment service and we are subscribed to it
$hosts = $service->get_remote_publishers();
if (empty($hosts)) {
echo $OUTPUT->box(get_string('nopublishers', 'mnetservice_enrol'), 'noticebox');
echo $OUTPUT->footer();
die();
}
$table = new html_table();
$table->attributes['class'] = 'generaltable remotehosts';
$table->head = array(
get_string('hostappname', 'mnetservice_enrol'),
get_string('hostname', 'mnetservice_enrol'),
get_string('hosturl', 'mnetservice_enrol'),
get_string('action')
);
foreach ($hosts as $host) {
$hostlink = html_writer::link(new moodle_url($host->hosturl), s($host->hosturl));
$editbtn = $OUTPUT->single_button(new moodle_url('/mnet/service/enrol/host.php', array('id'=>$host->id)),
get_string('editenrolments', 'mnetservice_enrol'), 'get');
$table->data[] = array(s($host->appname), s($host->hostname), $hostlink, $editbtn);
}
echo html_writer::table($table);
echo $OUTPUT->footer();
@@ -0,0 +1,47 @@
<?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/>.
/**
* @package mnetservice
* @subpackage enrolment
* @copyright 2010 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$string['availablecourseson'] = 'Available courses on {$a}';
$string['availablecoursesonnone'] = 'Remote host <a href="{$a->hosturl}">{$a->hostname}</a> does not offer any courses for our users.';
$string['clientname'] = 'Remote enrolments client';
$string['clientname_help'] = 'This tool allows you to enrol and unenrol your local users on remote hosts that allow you to do so via the \'MNet remote enrolments\' plugin.';
$string['editenrolments'] = 'Edit enrolments';
$string['hostappname'] = 'Application';
$string['hostname'] = 'Host name';
$string['hosturl'] = 'Remote host URL';
$string['nopublishers'] = 'No remote peers available.';
$string['noroamingusers'] = 'Users require the capability \'{$a}\' in the system context to be enrolled to remote courses, however there are currently no users with this capability. Click the continue button to assign the required capability to one or more roles on your site.';
$string['otherenrolledusers'] = 'Other enrolled users';
$string['pluginname'] = 'Remote enrolment service';
$string['refetch'] = 'Re-fetch up to date state from remote hosts';
$string['privacy:metadata:mnetservice_enrol_enrolments'] = 'Remote enrolment service';
$string['privacy:metadata:mnetservice_enrol_enrolments:enroltime'] = 'The time when the enrolment was modified';
$string['privacy:metadata:mnetservice_enrol_enrolments:enroltype'] = 'The enrolment type on the remote server used to enrol the user in their course';
$string['privacy:metadata:mnetservice_enrol_enrolments:hostid'] = 'The ID of the remote MNet host';
$string['privacy:metadata:mnetservice_enrol_enrolments:remotecourseid'] = 'The ID of the course on the remote server';
$string['privacy:metadata:mnetservice_enrol_enrolments:rolename'] = 'The name of role on the remote server';
$string['privacy:metadata:mnetservice_enrol_enrolments:tableexplanation'] = 'The Remote enrolment service stores information about enrolments of local users in courses on remote hosts.';
$string['privacy:metadata:mnetservice_enrol_enrolments:userid'] = 'The ID of the local user on this server';
+614
View File
@@ -0,0 +1,614 @@
<?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/>.
/**
* Provides various useful functionality to plugins that offer or use this MNet service
*
* Remote enrolment service is used by enrol_mnet plugin which publishes the server side
* methods. The client side is accessible from the admin tree.
*
* @package mnetservice
* @subpackage enrol
* @copyright 2010 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/user/selector/lib.php');
/**
* Singleton providing various functionality usable by plugin(s) implementing this MNet service
*/
class mnetservice_enrol {
/** @var mnetservice_enrol holds the singleton instance. */
protected static $singleton;
/** @var caches the result of {@link self::get_remote_subscribers()} */
protected $cachesubscribers = null;
/** @var caches the result of {@link self::get_remote_publishers()} */
protected $cachepublishers = null;
/**
* This is singleton, use {@link mnetservice_enrol::get_instance()}
*/
protected function __construct() {
}
/**
* @return mnetservice_enrol singleton instance
*/
public static function get_instance() {
if (is_null(self::$singleton)) {
self::$singleton = new self();
}
return self::$singleton;
}
/**
* Is this service enabled?
*
* Currently, this checks if whole MNet is available. In the future, additional
* checks can be done. Probably the field 'offer' should be checked but it does
* not seem to be used so far.
*
* @todo move this to some parent class once we have such
* @return bool
*/
public function is_available() {
global $CFG;
if (empty($CFG->mnet_dispatcher_mode) || $CFG->mnet_dispatcher_mode !== 'strict') {
return false;
}
return true;
}
/**
* Returns a list of remote servers that can enrol their users into our courses
*
* We must publish MNet service 'mnet_enrol' for the peers to allow them to enrol
* their users into our courses.
*
* @todo once the MNet core is refactored this may be part of a parent class
* @todo the name of the service should be changed to the name of this plugin
* @return array
*/
public function get_remote_subscribers() {
global $DB;
if (is_null($this->cachesubscribers)) {
$sql = "SELECT DISTINCT h.id, h.name AS hostname, h.wwwroot AS hosturl,
a.display_name AS appname
FROM {mnet_host} h
JOIN {mnet_host2service} hs ON h.id = hs.hostid
JOIN {mnet_service} s ON hs.serviceid = s.id
JOIN {mnet_application} a ON h.applicationid = a.id
WHERE s.name = 'mnet_enrol'
AND h.deleted = 0
AND hs.publish = 1";
$this->cachesubscribers = $DB->get_records_sql($sql);
}
return $this->cachesubscribers;
}
/**
* Returns a list of remote servers that offer their courses for our users
*
* We must subscribe MNet service 'mnet_enrol' for the peers to allow our users to enrol
* into their courses.
*
* @todo once the MNet core is refactored this may be part of a parent class
* @todo the name of the service should be changed to the name of this plugin
* @return array
*/
public function get_remote_publishers() {
global $DB;
if (is_null($this->cachepublishers)) {
$sql = "SELECT DISTINCT h.id, h.name AS hostname, h.wwwroot AS hosturl,
a.display_name AS appname
FROM {mnet_host} h
JOIN {mnet_host2service} hs ON h.id = hs.hostid
JOIN {mnet_service} s ON hs.serviceid = s.id
JOIN {mnet_application} a ON h.applicationid = a.id
WHERE s.name = 'mnet_enrol'
AND h.deleted = 0
AND hs.subscribe = 1";
$this->cachepublishers = $DB->get_records_sql($sql);
}
return $this->cachepublishers;
}
/**
* Fetches the information about the courses available on remote host for our students
*
* The information about remote courses available for us is cached in {mnetservice_enrol_courses}.
* This method either returns the cached information (typically when displaying the list to
* students) or fetch fresh data via new XML-RPC request (which updates the local cache, too).
* The lifetime of the cache is 1 day, so even if $usecache is set to true, the cache will be
* re-populated if we did not fetch from any server (not only the currently requested one)
* for some time.
*
* @param id $mnethostid MNet remote host id
* @param bool $usecache use cached data or invoke new XML-RPC?
* @uses mnet_xmlrpc_client Invokes XML-RPC request if the cache is not used
* @return array|string returned list or serialized array of mnet error messages
*/
public function get_remote_courses($mnethostid, $usecache=true) {
global $CFG, $DB; // $CFG needed!
$lastfetchcourses = get_config('mnetservice_enrol', 'lastfetchcourses');
if (empty($lastfetchcourses) or (time()-$lastfetchcourses > DAYSECS)) {
$usecache = false;
}
if ($usecache) {
return $DB->get_records('mnetservice_enrol_courses', array('hostid' => $mnethostid), 'sortorder, shortname');
}
// do not use cache - fetch fresh list from remote MNet host
require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
$peer = new mnet_peer();
if (!$peer->set_id($mnethostid)) {
return serialize(array('unknown mnet peer'));
}
$request = new mnet_xmlrpc_client();
$request->set_method('enrol/mnet/enrol.php/available_courses');
if ($request->send($peer)) {
$list = array();
$response = $request->response;
// get the currently cached courses key'd on remote id - only need remoteid and id fields
$cachedcourses = $DB->get_records('mnetservice_enrol_courses', array('hostid' => $mnethostid), 'remoteid', 'remoteid, id');
foreach ($response as &$remote) {
$course = new stdclass(); // record in our local cache
$course->hostid = $mnethostid;
$course->remoteid = (int)$remote['remoteid'];
$course->categoryid = (int)$remote['cat_id'];
$course->categoryname = substr($remote['cat_name'], 0, 255);
$course->sortorder = (int)$remote['sortorder'];
$course->fullname = substr($remote['fullname'], 0, 254);
$course->shortname = substr($remote['shortname'], 0, 100);
$course->idnumber = substr($remote['idnumber'], 0, 100);
$course->summary = $remote['summary'];
$course->summaryformat = empty($remote['summaryformat']) ? FORMAT_MOODLE : (int)$remote['summaryformat'];
$course->startdate = (int)$remote['startdate'];
$course->roleid = (int)$remote['defaultroleid'];
$course->rolename = substr($remote['defaultrolename'], 0, 255);
// We do not cache the following fields returned from peer in 2.0 any more
// not cached: cat_description
// not cached: cat_descriptionformat
// not cached: cost
// not cached: currency
if (empty($cachedcourses[$course->remoteid])) {
$course->id = $DB->insert_record('mnetservice_enrol_courses', $course);
} else {
$course->id = $cachedcourses[$course->remoteid]->id;
$DB->update_record('mnetservice_enrol_courses', $course);
}
$list[$course->remoteid] = $course;
}
// prune stale data from cache
if (!empty($cachedcourses)) {
foreach ($cachedcourses as $cachedcourse) {
if (!empty($list[$cachedcourse->remoteid])) {
unset($cachedcourses[$cachedcourse->remoteid]);
}
}
$staleremoteids = array_keys($cachedcourses);
if (!empty($staleremoteids)) {
list($sql, $params) = $DB->get_in_or_equal($staleremoteids, SQL_PARAMS_NAMED);
$select = "hostid=:hostid AND remoteid $sql";
$params['hostid'] = $mnethostid;
$DB->delete_records_select('mnetservice_enrol_courses', $select, $params);
}
}
// and return the fresh data
set_config('lastfetchcourses', time(), 'mnetservice_enrol');
return $list;
} else {
return serialize($request->error);
}
}
/**
* Updates local cache about enrolments of our users in remote courses
*
* The remote course must allow enrolments via our Remote enrolment service client.
* Because of legacy design of data structure returned by XML-RPC code, only one
* user enrolment per course is returned by 1.9 MNet servers. This may be an issue
* if the user is enrolled multiple times by various enrolment plugins. MNet 2.0
* servers do not use user name as array keys - they do not need to due to side
* effect of MDL-19219.
*
* @param id $mnethostid MNet remote host id
* @param int $remotecourseid ID of the course at the remote host
* @param bool $usecache use cached data or invoke new XML-RPC?
* @uses mnet_xmlrpc_client Invokes XML-RPC request
* @return bool|string true if success or serialized array of mnet error messages
*/
public function req_course_enrolments($mnethostid, $remotecourseid) {
global $CFG, $DB; // $CFG needed!
require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
if (!$DB->record_exists('mnetservice_enrol_courses', array('hostid'=>$mnethostid, 'remoteid'=>$remotecourseid))) {
return serialize(array('course not available for remote enrolments'));
}
$peer = new mnet_peer();
if (!$peer->set_id($mnethostid)) {
return serialize(array('unknown mnet peer'));
}
$request = new mnet_xmlrpc_client();
$request->set_method('enrol/mnet/enrol.php/course_enrolments');
$request->add_param($remotecourseid, 'int');
if ($request->send($peer)) {
$list = array();
$response = $request->response;
// prepare a table mapping usernames of our users to their ids
$usernames = array();
foreach ($response as $unused => $remote) {
if (!isset($remote['username'])) {
// see MDL-19219
return serialize(array('remote host running old version of mnet server - does not return username attribute'));
}
if ($remote['username'] == 'guest') { // we can not use $CFG->siteguest here
// do not try nasty things you bastard!
continue;
}
$usernames[$remote['username']] = $remote['username'];
}
if (!empty($usernames)) {
list($usql, $params) = $DB->get_in_or_equal($usernames, SQL_PARAMS_NAMED);
list($sort, $sortparams) = users_order_by_sql();
$params['mnetlocalhostid'] = $CFG->mnet_localhost_id;
$sql = "SELECT username,id
FROM {user}
WHERE mnethostid = :mnetlocalhostid
AND username $usql
AND deleted = 0
AND confirmed = 1
ORDER BY $sort";
$usersbyusername = $DB->get_records_sql($sql, array_merge($params, $sortparams));
} else {
$usersbyusername = array();
}
// populate the returned list and update local cache of enrolment records
foreach ($response as $remote) {
if (empty($usersbyusername[$remote['username']])) {
// we do not know this user or she is deleted or not confirmed or is 'guest'
continue;
}
$enrolment = new stdclass();
$enrolment->hostid = $mnethostid;
$enrolment->userid = $usersbyusername[$remote['username']]->id;
$enrolment->remotecourseid = $remotecourseid;
$enrolment->rolename = $remote['name']; // $remote['shortname'] not used
$enrolment->enroltime = $remote['timemodified'];
$enrolment->enroltype = $remote['enrol'];
$current = $DB->get_record('mnetservice_enrol_enrolments', array('hostid'=>$enrolment->hostid, 'userid'=>$enrolment->userid,
'remotecourseid'=>$enrolment->remotecourseid, 'enroltype'=>$enrolment->enroltype), 'id, enroltime');
if (empty($current)) {
$enrolment->id = $DB->insert_record('mnetservice_enrol_enrolments', $enrolment);
} else {
$enrolment->id = $current->id;
if ($current->enroltime != $enrolment->enroltime) {
$DB->update_record('mnetservice_enrol_enrolments', $enrolment);
}
}
$list[$enrolment->id] = $enrolment;
}
// prune stale enrolment records
if (empty($list)) {
$DB->delete_records('mnetservice_enrol_enrolments', array('hostid'=>$mnethostid, 'remotecourseid'=>$remotecourseid));
} else {
list($isql, $params) = $DB->get_in_or_equal(array_keys($list), SQL_PARAMS_NAMED, 'param', false);
$params['hostid'] = $mnethostid;
$params['remotecourseid'] = $remotecourseid;
$select = "hostid = :hostid AND remotecourseid = :remotecourseid AND id $isql";
$DB->delete_records_select('mnetservice_enrol_enrolments', $select, $params);
}
// store the timestamp of the recent fetch, can be used for cache invalidate purposes
set_config('lastfetchenrolments', time(), 'mnetservice_enrol');
// local cache successfully updated
return true;
} else {
return serialize($request->error);
}
}
/**
* Send request to enrol our user to the remote course
*
* Updates our remote enrolments cache if the enrolment was successful.
*
* @uses mnet_xmlrpc_client Invokes XML-RPC request
* @param object $user our user
* @param object $remotecourse record from mnetservice_enrol_courses table
* @return true|string true if success, error message from the remote host otherwise
*/
public function req_enrol_user(stdclass $user, stdclass $remotecourse) {
global $CFG, $DB;
require_once($CFG->dirroot.'/mnet/xmlrpc/client.php');
$peer = new mnet_peer();
$peer->set_id($remotecourse->hostid);
$request = new mnet_xmlrpc_client();
$request->set_method('enrol/mnet/enrol.php/enrol_user');
$request->add_param(mnet_strip_user((array)$user, mnet_fields_to_send($peer)));
$request->add_param($remotecourse->remoteid);
if ($request->send($peer) === true) {
if ($request->response === true) {
// cache the enrolment information in our table
$enrolment = new stdclass();
$enrolment->hostid = $peer->id;
$enrolment->userid = $user->id;
$enrolment->remotecourseid = $remotecourse->remoteid;
$enrolment->enroltype = 'mnet';
// $enrolment->rolename not known now, must be re-fetched
// $enrolment->enroltime not known now, must be re-fetched
$DB->insert_record('mnetservice_enrol_enrolments', $enrolment);
return true;
} else {
return serialize(array('invalid response: '.print_r($request->response, true)));
}
} else {
return serialize($request->error);
}
}
/**
* Send request to unenrol our user from the remote course
*
* Updates our remote enrolments cache if the unenrolment was successful.
*
* @uses mnet_xmlrpc_client Invokes XML-RPC request
* @param object $user our user
* @param object $remotecourse record from mnetservice_enrol_courses table
* @return true|string true if success, error message from the remote host otherwise
*/
public function req_unenrol_user(stdclass $user, stdclass $remotecourse) {
global $CFG, $DB;
require_once($CFG->dirroot.'/mnet/xmlrpc/client.php');
$peer = new mnet_peer();
$peer->set_id($remotecourse->hostid);
$request = new mnet_xmlrpc_client();
$request->set_method('enrol/mnet/enrol.php/unenrol_user');
$request->add_param($user->username);
$request->add_param($remotecourse->remoteid);
if ($request->send($peer) === true) {
if ($request->response === true) {
// clear the cached information
$DB->delete_records('mnetservice_enrol_enrolments',
array('hostid'=>$peer->id, 'userid'=>$user->id, 'remotecourseid'=>$remotecourse->remoteid, 'enroltype'=>'mnet'));
return true;
} else {
return serialize(array('invalid response: '.print_r($request->response, true)));
}
} else {
return serialize($request->error);
}
}
/**
* Prepares error messages returned by our XML-RPC requests to be send as debug info to {@see \moodle_exception()}
*
* MNet client-side methods in this class return request error as serialized array.
*
* @param string $error serialized array
* @return string
*/
public function format_error_message($errormsg) {
$errors = unserialize($errormsg);
$output = 'mnet_xmlrpc_client request returned errors:'."\n";
foreach ($errors as $error) {
$output .= "$error\n";
}
return $output;
}
}
/**
* Selector of our users enrolled into remote course via enrol_mnet plugin
*/
class mnetservice_enrol_existing_users_selector extends user_selector_base {
/** @var id of the MNet peer */
protected $hostid;
/** @var id of the course at the remote server */
protected $remotecourseid;
public function __construct($name, $options) {
$this->hostid = $options['hostid'];
$this->remotecourseid = $options['remotecourseid'];
parent::__construct($name, $options);
}
/**
* Find our users currently enrolled into the remote course
*
* @param string $search
* @return array
*/
public function find_users($search) {
global $DB;
list($wherecondition, $params) = $this->search_sql($search, 'u');
$params['hostid'] = $this->hostid;
$params['remotecourseid'] = $this->remotecourseid;
$fields = "SELECT ".$this->required_fields_sql("u");
$countfields = "SELECT COUNT(1)";
$sql = " FROM {user} u
JOIN {mnetservice_enrol_enrolments} e ON e.userid = u.id
WHERE e.hostid = :hostid AND e.remotecourseid = :remotecourseid
AND e.enroltype = 'mnet'
AND $wherecondition";
list($sort, $sortparams) = users_order_by_sql('u');
$order = " ORDER BY $sort";
if (!$this->is_validating()) {
$potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params);
if ($potentialmemberscount > 100) {
return $this->too_many_results($search, $potentialmemberscount);
}
}
$availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
if (empty($availableusers)) {
return array();
}
if ($search) {
$groupname = get_string('enrolledusersmatching', 'enrol', $search);
} else {
$groupname = get_string('enrolledusers', 'enrol');
}
return array($groupname => $availableusers);
}
protected function get_options() {
$options = parent::get_options();
$options['hostid'] = $this->hostid;
$options['remotecourseid'] = $this->remotecourseid;
$options['file'] = 'mnet/service/enrol/locallib.php';
return $options;
}
}
/**
* Selector of our users who could be enrolled into a remote course via their enrol_mnet
*/
class mnetservice_enrol_potential_users_selector extends user_selector_base {
/** @var id of the MNet peer */
protected $hostid;
/** @var id of the course at the remote server */
protected $remotecourseid;
public function __construct($name, $options) {
$this->hostid = $options['hostid'];
$this->remotecourseid = $options['remotecourseid'];
parent::__construct($name, $options);
}
/**
* Find our users who could be enrolled into the remote course
*
* Our users must have 'moodle/site:mnetlogintoremote' capability assigned.
* Remote users, guests, deleted and not confirmed users are not returned.
*
* @param string $search
* @return array
*/
public function find_users($search) {
global $CFG, $DB;
$systemcontext = context_system::instance();
$userids = get_users_by_capability($systemcontext, 'moodle/site:mnetlogintoremote', 'u.id');
if (empty($userids)) {
return array();
}
list($usql, $uparams) = $DB->get_in_or_equal(array_keys($userids), SQL_PARAMS_NAMED, 'uid');
list($wherecondition, $params) = $this->search_sql($search, 'u');
$params = array_merge($params, $uparams);
$params['hostid'] = $this->hostid;
$params['remotecourseid'] = $this->remotecourseid;
$params['mnetlocalhostid'] = $CFG->mnet_localhost_id;
$fields = "SELECT ".$this->required_fields_sql("u");
$countfields = "SELECT COUNT(1)";
$sql = " FROM {user} u
WHERE $wherecondition
AND u.mnethostid = :mnetlocalhostid
AND u.id $usql
AND u.id NOT IN (SELECT e.userid
FROM {mnetservice_enrol_enrolments} e
WHERE (e.hostid = :hostid AND e.remotecourseid = :remotecourseid))";
list($sort, $sortparams) = users_order_by_sql('u');
$order = " ORDER BY $sort";
if (!$this->is_validating()) {
$potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params);
if ($potentialmemberscount > 100) {
return $this->too_many_results($search, $potentialmemberscount);
}
}
$availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
if (empty($availableusers)) {
return array();
}
if ($search) {
$groupname = get_string('enrolcandidatesmatching', 'enrol', $search);
} else {
$groupname = get_string('enrolcandidates', 'enrol');
}
return array($groupname => $availableusers);
}
protected function get_options() {
$options = parent::get_options();
$options['hostid'] = $this->hostid;
$options['remotecourseid'] = $this->remotecourseid;
$options['file'] = 'mnet/service/enrol/locallib.php';
return $options;
}
}
+33
View File
@@ -0,0 +1,33 @@
.path-admin-mnet-service-enrol .singlebutton {
text-align: center;
}
.path-admin-mnet-service-enrol table.remotehosts,
.path-admin-mnet-service-enrol table.otherenrolledusers,
.path-admin-mnet-service-enrol table.remotecourses {
margin: 0 auto 1em auto;
}
.path-admin-mnet-service-enrol table.remotecourses th.categoryname {
text-align: left;
background-color: #f6f6f6;
}
.path-admin-mnet-service-enrol table.remotecourses td.c1 {
font-weight: bold;
}
.path-admin-mnet-service-enrol table.remotecourses th.categoryname img {
margin-right: 1em;
}
.path-admin-mnet-service-enrol .collapsibleregioncaption {
font-size: 110%;
font-weight: bold;
text-align: center;
}
.path-admin-mnet-service-enrol .collapsibleregioninner {
border: 1px solid #ddd;
padding: 1em;
}
.path-admin-mnet-service-enrol .collapsibleregion.remotecourse.summary {
margin: 0 10em;
}
.path-admin-mnet-service-enrol .roleassigntable {
margin: 1em auto;
}
@@ -0,0 +1,344 @@
<?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/>.
/**
* Privacy test for the mnetservice_enrol implementation of the privacy API.
*
* @package mnetservice_enrol
* @category test
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mnetservice_enrol\privacy;
defined('MOODLE_INTERNAL') || die();
use mnetservice_enrol\privacy\provider;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\writer;
use core_privacy\local\request\transform;
use core_privacy\tests\provider_testcase;
use core_privacy\local\request\approved_userlist;
/**
* Privacy test for the mnetservice_enrol.
*
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends provider_testcase {
/** @var stdClass the mnet host we are using to test. */
protected $mnethost;
/** @var stdClass the mnet service enrolment to test. */
protected $enrolment;
/**
* Test set up.
*
* This is executed before running any test in this file.
*/
public function setUp(): void {
global $DB;
// Add a mnet host.
$this->mnethost = new \stdClass();
$this->mnethost->name = 'A mnet host';
$this->mnethost->public_key = 'A random public key!';
$this->mnethost->id = $DB->insert_record('mnet_host', $this->mnethost);
}
/**
* Check that a user context is returned if there is any user data for this user.
*/
public function test_get_contexts_for_userid(): void {
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$this->assertEmpty(provider::get_contexts_for_userid($user->id));
// Create a test MNet service enrol enrolments.
$remotecourseid = 101;
$this->insert_mnetservice_enrol_courses($remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user->id, $remotecourseid);
$contextlist = provider::get_contexts_for_userid($user->id);
// Check that we only get back two context.
$this->assertCount(1, $contextlist);
// Check that the contexts are returned are the expected.
$usercontext = \context_user::instance($user->id);
$this->assertEquals($usercontext->id, $contextlist->get_contextids()[0]);
}
/**
* Test that user data is exported correctly.
*/
public function test_export_user_data(): void {
global $DB;
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$this->assertEmpty(provider::get_contexts_for_userid($user->id));
// Create a test MNet service enrol enrolments.
$remotecourseid = 101;
$this->insert_mnetservice_enrol_courses($remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user->id, $remotecourseid);
$subcontexts = [
get_string('privacy:metadata:mnetservice_enrol_enrolments', 'mnetservice_enrol')
];
$usercontext = \context_user::instance($user->id);
$writer = writer::with_context($usercontext);
$this->assertFalse($writer->has_any_data());
$approvedlist = new approved_contextlist($user, 'mnetservice_enrol', [$usercontext->id]);
provider::export_user_data($approvedlist);
$data = (array)$writer->get_data($subcontexts);
$this->assertCount(1, $data);
$this->assertEquals($this->mnethost->name, reset($data)->host);
$remotecoursename = $DB->get_field('mnetservice_enrol_courses', 'fullname',
array('remoteid' => $this->enrolment->remotecourseid));
$this->assertEquals($remotecoursename, reset($data)->remotecourseid);
$this->assertEquals($this->enrolment->rolename, reset($data)->rolename);
$this->assertEquals($this->enrolment->enroltype, reset($data)->enroltype);
$this->assertEquals(transform::datetime($this->enrolment->enroltime), reset($data)->enroltime);
}
/**
* Test deleting all user data for a specific context.
*/
public function test_delete_data_for_all_users_in_context(): void {
global $DB;
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();
$this->assertEmpty(provider::get_contexts_for_userid($user->id));
// Create a test MNet service enrol enrolments.
$remotecourseid = 101;
$this->insert_mnetservice_enrol_courses($remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user->id, $remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user2->id, $remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user3->id, $remotecourseid);
$usercontext = \context_user::instance($user->id);
// Get all user enrolments.
$userenrolments = $DB->get_records('mnetservice_enrol_enrolments', array());
$this->assertCount(3, $userenrolments);
// Get all user enrolments match with user.
$userenrolments = $DB->get_records('mnetservice_enrol_enrolments', array('userid' => $user->id));
$this->assertCount(1, $userenrolments);
// Delete everything for the first user context.
provider::delete_data_for_all_users_in_context($usercontext);
// Get all user enrolments match with user.
$userenrolments = $DB->get_records('mnetservice_enrol_enrolments', ['userid' => $user->id]);
$this->assertCount(0, $userenrolments);
// Get all user enrolments.
$userenrolments = $DB->get_records('mnetservice_enrol_enrolments', array());
$this->assertCount(2, $userenrolments);
}
/**
* This should work identical to the above test.
*/
public function test_delete_data_for_user(): void {
global $DB;
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();
$this->assertEmpty(provider::get_contexts_for_userid($user->id));
$remotecourseid = 101;
$this->insert_mnetservice_enrol_courses($remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user->id, $remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user2->id, $remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user3->id, $remotecourseid);
$remotecourseid2 = 102;
$this->insert_mnetservice_enrol_courses($remotecourseid2);
$this->insert_mnetservice_enrol_enrolments($user->id, $remotecourseid2);
$usercontext = \context_user::instance($user->id);
// Get all user enrolments.
$userenrolments = $DB->get_records('mnetservice_enrol_enrolments', array());
$this->assertCount(4, $userenrolments);
// Get all user enrolments match with user.
$userenrolments = $DB->get_records('mnetservice_enrol_enrolments', array('userid' => $user->id));
$this->assertCount(2, $userenrolments);
// Delete everything for the first user.
$approvedlist = new approved_contextlist($user, 'mnetservice_enrol', [$usercontext->id]);
provider::delete_data_for_user($approvedlist);
// Get all user enrolments match with user.
$userenrolments = $DB->get_records('mnetservice_enrol_enrolments', ['userid' => $user->id]);
$this->assertCount(0, $userenrolments);
// Get all user enrolments accounts.
$userenrolments = $DB->get_records('mnetservice_enrol_enrolments', array());
$this->assertCount(2, $userenrolments);
}
/**
* Test that only users within a course context are fetched.
*/
public function test_get_users_in_context(): void {
$this->resetAfterTest();
$component = 'mnetservice_enrol';
// Create a user.
$user = $this->getDataGenerator()->create_user();
$usercontext = \context_user::instance($user->id);
// Create user2.
$user2 = $this->getDataGenerator()->create_user();
$userlist = new \core_privacy\local\request\userlist($usercontext, $component);
provider::get_users_in_context($userlist);
$this->assertCount(0, $userlist);
// Create a test MNet service enrol enrolments.
$remotecourseid = 101;
$this->insert_mnetservice_enrol_courses($remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user->id, $remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user2->id, $remotecourseid);
// The list of users within the user context should contain only user.
provider::get_users_in_context($userlist);
$this->assertCount(1, $userlist);
$this->assertFalse(in_array($user2->id, $userlist->get_userids()));
$this->assertTrue(in_array($user->id, $userlist->get_userids()));
// The list of users within the system context should be empty.
$systemcontext = \context_system::instance();
$userlist2 = new \core_privacy\local\request\userlist($systemcontext, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(0, $userlist2);
}
/**
* Test that data for users in approved userlist is deleted.
*/
public function test_delete_data_for_users(): void {
$this->resetAfterTest();
$component = 'mnetservice_enrol';
// Create user1.
$user1 = $this->getDataGenerator()->create_user();
$usercontext1 = \context_user::instance($user1->id);
// Create user2.
$user2 = $this->getDataGenerator()->create_user();
$usercontext2 = \context_user::instance($user2->id);
// Create a test MNet service enrol enrolments.
$remotecourseid = 101;
$this->insert_mnetservice_enrol_courses($remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user1->id, $remotecourseid);
$this->insert_mnetservice_enrol_enrolments($user2->id, $remotecourseid);
$userlist1 = new \core_privacy\local\request\userlist($usercontext1, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(1, $userlist1);
$expected = [$user1->id];
$actual = $userlist1->get_userids();
$this->assertEquals($expected, $actual);
$userlist2 = new \core_privacy\local\request\userlist($usercontext2, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(1, $userlist2);
$expected = [$user2->id];
$actual = $userlist2->get_userids();
$this->assertEquals($expected, $actual);
// Convert $userlist1 into an approved_contextlist.
$approvedlist1 = new approved_userlist($usercontext1, $component, $userlist1->get_userids());
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist1);
// Re-fetch users in usercontext1.
$userlist1 = new \core_privacy\local\request\userlist($usercontext1, $component);
provider::get_users_in_context($userlist1);
// The user data in usercontext1 should be deleted.
$this->assertCount(0, $userlist1);
// Re-fetch users in usercontext2.
$userlist2 = new \core_privacy\local\request\userlist($usercontext2, $component);
provider::get_users_in_context($userlist2);
// The user data in usercontext2 should be still present.
$this->assertCount(1, $userlist2);
// Convert $userlist2 into an approved_contextlist in the system context.
$systemcontext = \context_system::instance();
$approvedlist3 = new approved_userlist($systemcontext, $component, $userlist2->get_userids());
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist3);
// Re-fetch users in usercontext2.
$userlist2 = new \core_privacy\local\request\userlist($usercontext2, $component);
provider::get_users_in_context($userlist2);
// The user data in systemcontext should not be deleted.
$this->assertCount(1, $userlist2);
}
/**
* Help function to create a simulation of MNet service enrol.
* Create a Dummy Enrol into mnetservice_enrol_enrolments.
*
* @param int $userid Userid.
* @param int $remotecourseid Remotecourseid.
*/
protected function insert_mnetservice_enrol_enrolments($userid, $remotecourseid) {
global $DB;
// Create a test MNet service enrol enrolments.
$this->enrolment = new \stdClass();
$this->enrolment->hostid = $this->mnethost->id;
$this->enrolment->userid = $userid;
$this->enrolment->remotecourseid = $remotecourseid;
$this->enrolment->rolename = 'student';
$this->enrolment->enroltime = time();
$this->enrolment->enroltype = 'mnet';
$DB->insert_record('mnetservice_enrol_enrolments', $this->enrolment);
}
/**
* Help function to create a simualtion of MNet service enrol.
* Create a Dummy Course into mnetservice_enrol_courses.
* Important: The real course is on the host.
*
* @param int $remoteid Remote courseid.
*/
protected function insert_mnetservice_enrol_courses($remoteid) {
global $DB;
// Create a Dummy Remote Course to test.
$course = new \stdClass();
$course->hostid = $this->mnethost->id;
$course->remoteid = $remoteid;
$course->categoryid = 1;
$course->categoryname = get_string('defaultcategoryname');
$course->sortorder = 10001;
$course->fullname = 'Test Remote Course '.$remoteid;
$course->shortname = 'testremotecourse '.$remoteid;
$course->idnumber = 'IdnumberRemote '.$remoteid;
$course->summary = 'TestSummaryRemote '.$remoteid;
$course->summaryformat = FORMAT_MOODLE;
$course->startdate = time();
$course->roleid = 5;
$course->rolename = 'student';
$DB->insert_record('mnetservice_enrol_courses', $course);
}
}
+28
View File
@@ -0,0 +1,28 @@
<?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/>.
/**
* @package mnetservice
* @subpackage enrol
* @copyright 2010 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024041600; // Requires this Moodle version.
$plugin->component = 'mnetservice_enrol'; // Full name of the plugin (used for diagnostics)