NOBUG xmldb editor - make php code generated to follow the 2-slash coding style
[moodle.git] / enrol / mnet / enrol.php
1 <?php
2 // The following flags are set in the configuration
3 // $config->allow_allcourses:       expose all courses to external enrolment
4 // $config->allowed_categories:     serialised array of courses allowed
5 // $config->allowed_courses:        serialised array of courses allowed
7 class enrolment_plugin_mnet {
9     /** * mnet environment - constructor makes sure its set up */
10     private $mnet;
12     function __construct() {
13         $this->mnet = get_mnet_environment();
14     }
16     /// Override the base config_form() function
17     function config_form($frm) {
18         global $CFG, $OUTPUT, $PAGE;
20        $vars = array('enrol_mnet_allow_allcourses',
21                      'enrol_mnet_allowed_categories',
22                      'enrol_mnet_allowed_courses');
24         foreach ($vars as $var) {
25             if (!isset($frm->$var)) {
26                 $frm->$var = '';
27             }
28         }
30         $mnethosts = $this->list_remote_servers();
32         include ("$CFG->dirroot/enrol/mnet/config.html");
33     }
36     /// Override the base process_config() function
37     function process_config($config) {
39         if (!isset($config->enrol_mnet_allow_allcourses)) {
40             $config->enrol_mnet_allow_allcourses = false;
41         }
42         set_config('enrol_mnet_allow_allcourses', $config->enrol_mnet_allow_allcourses);
44         if (!isset($config->enrol_mnet_allowed_categories)) {
45             $config->enrol_mnet_allowed_categories = '';
46         }
47         set_config('enrol_mnet_allowed_categories', $config->enrol_mnet_allowed_categories);
49         if (!isset($config->enrol_mnet_allowed_courses)) {
50             $config->enrol_mnet_allowed_courses = '';
51         }
52         set_config('enrol_mnet_allowed_courses', $config->enrol_mnet_allowed_courses);
54         return true;
56     }
58     /// Override the get_access_icons() function
59     function get_access_icons($course) {
60     }
62     /**
63      * Override the base cron() function
64      */
65     //function cron() {
66     //
67     //} // end of cron()
71     /***
72      *** MNET functions
73      ***
74      ***/
76     /**
77     * Returns a list of all courses available for remote login
78     *
79     * @return array Array of courses
80     */
81     function available_courses() {
82         global $CFG, $DB;
84         if (!empty($CFG->enrol_mnet_allow_allcourses)) {
86             $query =
87             "SELECT
88                 co.id          AS remoteid,
89                 ca.id          AS cat_id,
90                 ca.name        AS cat_name,
91                 ca.description AS cat_description,
92                 co.sortorder,
93                 co.fullname,
94                 co.shortname,
95                 co.idnumber,
96                 co.summary,
97                 co.startdate,
98                 co.cost,
99                 co.currency,
100                 co.defaultrole AS defaultroleid,
101                 r.name         AS defaultrolename
102             FROM
103                 {course_categories} ca
104             JOIN
105                 {course} co ON ca.id = co.category
106             LEFT JOIN
107                 {role} r ON r.id = co.defaultrole
108             WHERE
109                 co.visible = 1 AND
110                 co.enrollable = 1
111             ORDER BY
112                 sortorder ASC
113                 ";
115             return $DB->get_records_sql($query);
117         } elseif (!empty($CFG->enrol_mnet_allowed_categories)) {
119             $cats = preg_split('/\s*,\s*/', $CFG->enrol_mnet_allowed_categories);
120             for ($n=0;$n < count($cats); $n++) {
121                 $cats[$n] = " ca.path LIKE '%/" . (int)$cats[$n] . "/%' ";
122             }
123             $cats = join(' OR ', $cats);
125             $query =
126             "SELECT
127                 id, name
128             FROM
129                 {course_categories} ca
130             WHERE
131                 ca.id IN ({$CFG->enrol_mnet_allowed_categories})
132                 OR ( $cats )
133             ORDER BY
134                 path ASC,
135                 depth ASC
136                 ";
137             unset($cats);
139             $rs = $DB->get_records_sql($query);
141             if (!empty($rs)) {
142                 $cats = array_keys($rs);
143             }
144             $where = ' AND ( ca.id IN (' . join(',', $cats) . ') ';
147             if (!empty($CFG->enrol_mnet_allowed_courses)) {
148                 $where .=  " OR co.id in ({$CFG->enrol_mnet_allowed_courses}) ";
149             }
151             $where .= ')';
153             $query =
154             "SELECT
155                 co.id as remoteid,
156                 ca.id as cat_id,
157                 ca.name as cat_name,
158                 ca.description as cat_description,
159                 co.sortorder,
160                 co.fullname,
161                 co.shortname,
162                 co.idnumber,
163                 co.summary,
164                 co.startdate,
165                 co.cost,
166                 co.currency,
167                 co.defaultrole as defaultroleid,
168                 r.name
169             FROM
170                 {course_categories} ca
171             JOIN
172                 {course} co ON ca.id = co.category
173             LEFT JOIN
174                 {role} r ON r.id = co.defaultrole
175             WHERE
176                 co.visible = 1 AND
177                 co.enrollable = 1 $where
178             ORDER BY
179                 sortorder ASC
180                 ";
182             return $DB->get_records_sql($query);
184         } elseif (!empty($CFG->enrol_mnet_allowed_courses)) {
186             $query =
187                 "SELECT
188                     co.id as remoteid,
189                     ca.id as cat_id,
190                     ca.name as cat_name,
191                     ca.description as cat_description,
192                     co.sortorder,
193                     co.fullname,
194                     co.shortname,
195                     co.idnumber,
196                     co.summary,
197                     co.startdate,
198                     co.cost,
199                     co.currency,
200                     co.defaultrole as defaultroleid,
201                     r.name
202                 FROM
203                     {course_categories} ca
204                 JOIN
205                     {course} co ON ca.id = co.category
206                 LEFT JOIN
207                     {role} r ON r.id = co.defaultrole
208                 WHERE
209                     co.visible = 1 AND
210                     co.enrollable = 1 AND
211                     co.id IN ({$CFG->enrol_mnet_allowed_courses})
212                 ORDER BY
213                     sortorder ASC
214                     ";
216             return $DB->get_records_sql($query);
218         }
220         return array();
221     }
223     /**
224      *
225      */
226     function user_enrolments($userid) {
227         return array();
228     }
230     /**
231      * Get a list of users from the client server who are enrolled in a course
232      *
233      * @param   int     $courseid   The Course ID
234      * @param   string  $roles      Comma-separated list of role shortnames
235      * @return  array               Array of usernames who are homed on the
236      *                              client machine
237      */
238     function course_enrolments($courseid, $roles = '') {
239         global $CFG, $DB;
241         if (! $course = $DB->get_record('course', array('id'=>$courseid))) {
242             return 'no course';
243             //error("That's an invalid course id");
244         }
246         $remoteclient = get_mnet_remote_client();
248         $context = get_context_instance(CONTEXT_COURSE, $courseid);
250         $sql = "
251                 SELECT
252                     u.id,
253                     u.username,
254                     a.enrol,
255                     a.timemodified,
256                     r.name,
257                     r.shortname
258                 FROM
259                     {role_assignments} a,
260                     {role} r,
261                     {user} u
262                 WHERE
263                     a.contextid = {$context->id} AND
264                     a.roleid = r.id AND
265                     a.userid = u.id AND
266                     u.mnethostid = '{$remoteclient->id}'
267                     ";
269         if(!empty($roles)) {
270             // $default_role = get_default_course_role($course); ???
271             $sql .= " AND
272                     a.roleid in ('".str_replace(',',  "', '",  $roles)."')";
273         }
275         $enrolments = $DB->get_records_sql($sql);
277         $returnarray = array();
278         foreach($enrolments as $user) {
279             $returnarray[$user->username] = array('enrol' => $user->enrol,
280                                                   'timemodified' => $user->timemodified,
281                                                   'shortname' => $user->shortname,
282                                                   'username' => $user->username,
283                                                   'name' => $user->name);
284         }
285         return $returnarray;
286     }
288     /**
289     * Enrols user to course with the default role
290     *
291     * @param string $username   The username of the remote use
292     * @param int    $courseid   The id of the local course
293     * @return bool              Whether the enrolment has been successful
294     */
295     function enrol_user($user, $courseid) {
296         global $DB;
297         $remoteclient = get_mnet_remote_client();
299         $userrecord = $DB->get_record('user',array('username'=>$user['username'], 'mnethostid'=>$remoteclient->id));
301         if ($userrecord == false) {
302             $userrecord = mnet_strip_user((object)$user, mnet_fields_to_import($remoteclient));
303             /* there used to be a setting in auth_mnet called auto_add_remote_users
304              * which we should have been checking here (but weren't).
305              * this setting has now been removed. See MDL-21327
306              */
307             $userrecord->mnethostid = $remoteclient->id;
309             if ($userrecord->id = $DB->insert_record('user', $userrecord)) {
310                 $userrecord = $DB->get_record('user', array('id'=>$userrecord->id));
311             } else {
312                 throw new mnet_server_exception(5011, 'couldnotcreateuser', 'enrol_mnet');
313             }
314         }
316         if (! $course = $DB->get_record('course', array('id'=>$courseid))) {
317             throw new mnet_server_exception(5012, 'coursenotfound', 'enrol_mnet');
318         }
320         $courses = $this->available_courses();
322         if (!empty($courses[$courseid])) {
323             if (enrol_into_course($course, $userrecord, 'mnet')) {
324                 return true;
325             }
326             throw new mnet_server_exception(5016, 'couldnotenrol', 'enrol_mnet');
327         }
328         throw new mnet_server_exception(5013, 'courseunavailable', 'enrol_mnet');
329     }
331     /**
332     * Unenrol a user from a course
333     *
334     * @param string $username   The username
335     * @param int    $courseid   The id of the local course
336     * @return bool              Whether the user can login from the remote host
337     */
338     function unenrol_user($username, $courseid) {
339         global $DB;
340         $remoteclient = get_mnet_remote_client();
342         if (!$userrecord = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$remoteclient->id))) {
343             throw new mnet_exception(5014, 'usernotfound', 'enrol_mnet');
344         }
346         if (! $course = $DB->get_record('course', array('id'=>$courseid))) {
347             throw new mnet_server_exception(5012, 'coursenotfound', 'enrol_mnet');
348         }
350         $context = get_context_instance(CONTEXT_COURSE, $course->id);
352         // Are we a *real* user or the shady MNET Daemon?
353         // require_capability('moodle/role:assign', $context, NULL, false);
355         role_unassign_all(array('userid'=>$userrecord->id, 'contextiod'=>$context->id, 'component'=>'enrol_mnet'), true, true);
357         return true;
358     }
360     /***
361      *** Client RPC behaviour
362      ***
363      ***
364      ***/
366     /**
367     * Lists remote servers we use 'enrol' services from.
368     *
369     * @return array
370     */
371     function list_remote_servers() {
372         global $CFG, $DB;
374         $sql = "
375             SELECT DISTINCT
376                 h.id,
377                 h.name
378             FROM
379                 {mnet_host} h,
380                 {mnet_host2service} h2s,
381                 {mnet_service} s
382             WHERE
383                 h.id          = h2s.hostid   AND
384                 h2s.serviceid = s.id         AND
385                 s.name        = 'mnet_enrol' AND
386                 h2s.subscribe = 1";
388         $res = $DB->get_records_sql($sql);
389         if (is_array($res)) {
390             return $res;
391         } else {
392             return array();
393         }
394     }
396     /**
397     * Does Foo
398     *
399     * @param int    $mnethostid The id of the remote mnethost
400     * @return array              Whether the user can login from the remote host
401     */
402     function fetch_remote_courses($mnethostid) {
403         global $CFG, $USER, $DB;
404         require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
406         // get the Service Provider info
407         $mnet_sp = new mnet_peer();
408         $mnet_sp->set_id($mnethostid);
410         // set up the RPC request
411         $mnetrequest = new mnet_xmlrpc_client();
412         $mnetrequest->set_method('enrol/mnet/enrol.php/available_courses');
414         // Initialise $message
415         $message = '';
417         // TODO: cache for a while (10 minutes?)
419         // Thunderbirds are go! Do RPC call and store response
420         if ($mnetrequest->send($mnet_sp) === true) {
421             $courses = $mnetrequest->response;
423             // get the cached courses key'd on remote id - only need remoteid and id fields
424             $cachedcourses = $DB->get_records('mnet_enrol_course', array('hostid'=>$mnethostid), 'remoteid', 'remoteid, id' );
426             // Update cache and transform $courses into objects
427             // in-place for the benefit of our caller...
428             for ($n=0;$n<count($courses);$n++) {
430                 $course = &$courses[$n];
432                 // add/update cached data in mnet_enrol_courses
433                 // sanitise data
434                 $course = (object)$course;
435                 $course->remoteid        = (int)$course->remoteid;
436                 $course->hostid          = $mnethostid;
437                 $course->cat_id          = (int)$course->cat_id;
438                 $course->sortorder       = (int)$course->sortorder ;
439                 $course->startdate       = (int)$course->startdate;
440                 $course->cost            = (int)$course->cost;
441                 $course->defaultroleid   = (int)$course->defaultroleid;
443                 // sanitise strings for DB NOTE - these are not sane
444                 // for printing, so we'll use a different object
445                 $dbcourse = clone($course);
446                 $dbcourse->cat_name        = substr($dbcourse->cat_name,0,255);
447                 $dbcourse->cat_description = $dbcourse->cat_description;
448                 $dbcourse->fullname        = substr($dbcourse->fullname,0,254);
449                 $dbcourse->shortname       = substr($dbcourse->shortname,0,15);
450                 $dbcourse->idnumber        = substr($dbcourse->idnumber,0,100);
451                 $dbcourse->summary         = $dbcourse->summary;
452                 $dbcourse->currency        = substr($dbcourse->currency,0,3);
453                 $dbcourse->defaultrolename = substr($dbcourse->defaultrolename,0,255);
455                 // insert or update
456                 if (empty($cachedcourses[$course->remoteid])) {
457                     $course->id = $DB->insert_record('mnet_enrol_course', $dbcourse);
458                 } else {
459                     $course->id = $dbcourse->id = $cachedcourses[$course->remoteid]->id;
460                     $cachedcourses[$course->remoteid]->seen=true;
461                     $DB->update_record('mnet_enrol_course', $dbcourse);
462                 }
463                 // free tmp obj
464                 unset($dbcourse);
465             }
467             // prune stale data from cache
468             if (!empty($cachedcourses)) {
469                 $stale = array();
470                 foreach ($cachedcourses as $id => $cc) {
471                     // TODO: maybe set a deleted flag instead
472                     if (empty($cc->seen)) {
473                         $stale[] = $cc->id;
474                     }
475                 }
476                 if (!empty($stale)) {
477                     $DB->delete_records_select('mnet_enrol_course', 'id IN ('.join(',',$stale).')');
478                 }
479             }
481             return $courses;
482         } else {
483             foreach ($mnetrequest->error as $errormessage) {
484                 list($code, $errormessage) = array_map('trim',explode(':', $errormessage, 2));
485                 $message .= "ERROR $code:<br/>$errormessage<br/>";
486             }
487             print_error("rpcerror", '', '', $message);
488         }
489         return false;
490     }
492     /**
493     * Does Foo
494     *
495     * @param int    $mnethostid The id of the remote mnethost
496     * @return array              Whether the user can login from the remote host
497     */
498     function req_enrol_user($userid, $courseid) {
499         global $CFG, $USER, $DB;
500         require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
502         // Prepare a user record
503         // in case the remote host doesn't have it
504         $user = $DB->get_record('user', array('id'=>$userid));
505         $user = (array)$user;
507         $course = $DB->get_record('mnet_enrol_course', array('id'=>$courseid));
509         // get the Service Provider info
510         $mnet_sp = new mnet_peer();
511         $mnet_sp->set_id($course->hostid);
513         // set up the RPC request
514         $mnetrequest = new mnet_xmlrpc_client();
515         $mnetrequest->set_method('enrol/mnet/enrol.php/enrol_user');
516         $mnetrequest->add_param(mnet_strip_user($user, mnet_fields_to_send($mnet_sp)));
517         $mnetrequest->add_param($course->remoteid);
519         // Thunderbirds are go! Do RPC call and store response
520         if ($mnetrequest->send($mnet_sp) === true) {
521             if ($mnetrequest->response == true) {
522                 // now store it in the mnet_enrol_assignments table
523                 $assignment = new StdClass;
524                 $assignment->userid = $userid;
525                 $assignment->hostid = $course->hostid;
526                 $assignment->courseid = $course->id;
527                 $assignment->enroltype = 'mnet';
528                 // TODO: other fields
529                 if ($DB->insert_record('mnet_enrol_assignments', $assignment)) {
530                     return true;
531                 }
532             }
533         }
535         return false;
536     }
538     /**
539     * Does Foo
540     *
541     * @param int    $mnethostid The id of the remote mnethost
542     * @return array              Whether the user can login from the remote host
543     */
544     function req_unenrol_user($userid, $courseid) {
545         global $CFG, $USER, $DB;
546         require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
548         // in case the remote host doesn't have it
549         $username = $DB->get_field('user', 'username', array('id'=>$userid));
551         $course = $DB->get_record('mnet_enrol_course', array('id'=>$courseid));
553         // get the Service Provider info
554         $mnet_sp = new mnet_peer();
555         $mnet_sp->set_id($course->hostid);
557         // set up the RPC request
558         $mnetrequest = new mnet_xmlrpc_client();
559         $mnetrequest->set_method('enrol/mnet/enrol.php/unenrol_user');
560         $mnetrequest->add_param($username);
561         $mnetrequest->add_param($course->remoteid);
563         // TODO - prevent removal of enrolments that are not of
564         // type mnet...
567         // Thunderbirds are go! Do RPC call and store response
568         if ($mnetrequest->send($mnet_sp) === true) {
569             if ($mnetrequest->response == true) {
570                 // remove enrolment cached in mnet_enrol_assignments
571                 $DB->delete_records_select('mnet_enrol_assignments',
572                                       "userid=? AND courseid=?", array($userid, $course->id));
574                 return true;
575             }
576         }
577         return false;
578     }
580 } // end of class