f224f0a52d972f80fac04c19cdf5146d9903cc60
[moodle.git] / enrol / guest / lib.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Guest access plugin.
19  *
20  * This plugin does not add any entries into the user_enrolments table,
21  * the access control is granted on the fly via the tricks in require_login().
22  *
23  * @package    enrol_guest
24  * @copyright  2010 Petr Skoda  {@link http://skodak.org}
25  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26  */
28 defined('MOODLE_INTERNAL') || die();
30 class enrol_guest_plugin extends enrol_plugin {
32     /**
33      * Returns optional enrolment information icons.
34      *
35      * This is used in course list for quick overview of enrolment options.
36      *
37      * We are not using single instance parameter because sometimes
38      * we might want to prevent icon repetition when multiple instances
39      * of one type exist. One instance may also produce several icons.
40      *
41      * @param array $instances all enrol instances of this type in one course
42      * @return array of pix_icon
43      */
44     public function get_info_icons(array $instances) {
45         foreach ($instances as $instance) {
46             if ($instance->password !== '') {
47                 return array(new pix_icon('withpassword', get_string('guestaccess_withpassword', 'enrol_guest'), 'enrol_guest'));
48             } else {
49                 return array(new pix_icon('withoutpassword', get_string('guestaccess_withoutpassword', 'enrol_guest'), 'enrol_guest'));
50             }
51         }
52     }
54     public function enrol_user(stdClass $instance, $userid, $roleid = null, $timestart = 0, $timeend = 0, $status = null, $recovergrades = null) {
55         // no real enrolments here!
56         return;
57     }
59     public function unenrol_user(stdClass $instance, $userid) {
60         // nothing to do, we never enrol here!
61         return;
62     }
64     /**
65      * Attempt to automatically gain temporary guest access to course,
66      * calling code has to make sure the plugin and instance are active.
67      *
68      * @param stdClass $instance course enrol instance
69      * @return bool|int false means no guest access, integer means end of cached time
70      */
71     public function try_guestaccess(stdClass $instance) {
72         global $USER, $CFG;
74         $allow = false;
76         if ($instance->password === '') {
77             $allow = true;
79         } else if (isset($USER->enrol_guest_passwords[$instance->id])) { // this is a hack, ideally we should not add stuff to $USER...
80             if ($USER->enrol_guest_passwords[$instance->id] === $instance->password) {
81                 $allow = true;
82             }
83         }
85         if ($allow) {
86             // Temporarily assign them some guest role for this context
87             $context = context_course::instance($instance->courseid);
88             load_temp_course_role($context, $CFG->guestroleid);
89             return ENROL_MAX_TIMESTAMP;
90         }
92         return false;
93     }
95     /**
96      * Returns link to page which may be used to add new instance of enrolment plugin in course.
97      * @param int $courseid
98      * @return moodle_url page url
99      */
100     public function get_newinstance_link($courseid) {
101         global $DB;
103         $context = context_course::instance($courseid, MUST_EXIST);
105         if (!has_capability('moodle/course:enrolconfig', $context) or !has_capability('enrol/guest:config', $context)) {
106             return NULL;
107         }
109         if ($DB->record_exists('enrol', array('courseid'=>$courseid, 'enrol'=>'guest'))) {
110             return NULL;
111         }
113         return new moodle_url('/enrol/guest/addinstance.php', array('sesskey'=>sesskey(), 'id'=>$courseid));
114     }
116     /**
117      * Creates course enrol form, checks if form submitted
118      * and enrols user if necessary. It can also redirect.
119      *
120      * @param stdClass $instance
121      * @return string html text, usually a form in a text box
122      */
123     public function enrol_page_hook(stdClass $instance) {
124         global $CFG, $OUTPUT, $SESSION, $USER;
126         if ($instance->password === '') {
127             return null;
128         }
130         if (isset($USER->enrol['tempguest'][$instance->courseid]) and $USER->enrol['tempguest'][$instance->courseid] > time()) {
131             // no need to show the guest access when user can already enter course as guest
132             return null;
133         }
135         require_once("$CFG->dirroot/enrol/guest/locallib.php");
136         $form = new enrol_guest_enrol_form(NULL, $instance);
137         $instanceid = optional_param('instance', 0, PARAM_INT);
139         if ($instance->id == $instanceid) {
140             if ($data = $form->get_data()) {
141                 // add guest role
142                 $context = context_course::instance($instance->courseid);
143                 $USER->enrol_guest_passwords[$instance->id] = $data->guestpassword; // this is a hack, ideally we should not add stuff to $USER...
144                 if (isset($USER->enrol['tempguest'][$instance->courseid])) {
145                     remove_temp_course_roles($context);
146                 }
147                 load_temp_course_role($context, $CFG->guestroleid);
148                 $USER->enrol['tempguest'][$instance->courseid] = ENROL_MAX_TIMESTAMP;
150                 // go to the originally requested page
151                 if (!empty($SESSION->wantsurl)) {
152                     $destination = $SESSION->wantsurl;
153                     unset($SESSION->wantsurl);
154                 } else {
155                     $destination = "$CFG->wwwroot/course/view.php?id=$instance->courseid";
156                 }
157                 redirect($destination);
158             }
159         }
161         ob_start();
162         $form->display();
163         $output = ob_get_clean();
165         return $OUTPUT->box($output, 'generalbox');
166     }
168     /**
169      * Adds enrol instance UI to course edit form
170      *
171      * @param object $instance enrol instance or null if does not exist yet
172      * @param MoodleQuickForm $mform
173      * @param object $data
174      * @param object $context context of existing course or parent category if course does not exist
175      * @return void
176      */
177     public function course_edit_form($instance, MoodleQuickForm $mform, $data, $context) {
179         $i = isset($instance->id) ? $instance->id : 0;
181         if (!$i and !$this->get_config('defaultenrol')) {
182             return;
183         }
185         $header = $this->get_instance_name($instance);
186         if (!$i) {
187             $config = guess_if_creator_will_have_course_capability('enrol/guest:config', $context);
188         } else {
189             $config = has_capability('enrol/guest:config', $context);
190         }
192         $mform->addElement('header', 'enrol_guest_header_'.$i, $header);
195         $options = array(ENROL_INSTANCE_ENABLED  => get_string('yes'),
196                          ENROL_INSTANCE_DISABLED => get_string('no'));
197         $mform->addElement('select', 'enrol_guest_status_'.$i, get_string('status', 'enrol_guest'), $options);
198         $mform->addHelpButton('enrol_guest_status_'.$i, 'status', 'enrol_guest');
199         $mform->setDefault('enrol_guest_status_'.$i, $this->get_config('status'));
200         $mform->setAdvanced('enrol_guest_status_'.$i, $this->get_config('status_adv'));
201         if (!$config) {
202             $mform->hardFreeze('enrol_guest_status_'.$i);
203             if (!$i) {
204                 $mform->setConstant('enrol_guest_status_'.$i, $this->get_config('status'));
205             } else {
206                 $mform->setConstant('enrol_guest_status_'.$i, $instance->status);
207             }
208         }
210         $mform->addElement('passwordunmask', 'enrol_guest_password_'.$i, get_string('password', 'enrol_guest'));
211         $mform->addHelpButton('enrol_guest_password_'.$i, 'password', 'enrol_guest');
212         if (!$config) {
213             $mform->hardFreeze('enrol_guest_password_'.$i);
214             if (!$i) {
215                 if ($this->get_config('requirepassword')) {
216                     $password = generate_password(20);
217                 } else {
218                     $password = '';
219                 }
220                 $mform->setConstant('enrol_guest_password_'.$i, $password);
221             } else {
222                 $mform->setConstant('enrol_guest_password_'.$i, $instance->password);
223             }
224         } else {
225             $mform->disabledIf('enrol_guest_password_'.$i, 'enrol_guest_status_'.$i, 'noteq', ENROL_INSTANCE_ENABLED);
226         }
229         // now add all values from enrol table
230         if ($instance) {
231             foreach($instance as $key=>$val) {
232                 $data->{'enrol_guest_'.$key.'_'.$i} = $val;
233             }
234         }
235     }
237     /**
238      * Validates course edit form data
239      *
240      * @param object $instance enrol instance or null if does not exist yet
241      * @param array $data
242      * @param object $context context of existing course or parent category if course does not exist
243      * @return array errors array
244      */
245     public function course_edit_validation($instance, array $data, $context) {
246         $errors = array();
248         if (!has_capability('enrol/guest:config', $context)) {
249             // we are going to ignore the data later anyway, they would nto be able to fix the form anyway
250             return $errors;
251         }
253         $i = isset($instance->id) ? $instance->id : 0;
255         if (!isset($data['enrol_guest_status_'.$i])) {
256             return $errors;
257         }
259         $password = empty($data['enrol_guest_password_'.$i]) ? '' : $data['enrol_guest_password_'.$i];
260         $checkpassword = false;
262         if ($instance) {
263             if ($data['enrol_guest_status_'.$i] == ENROL_INSTANCE_ENABLED) {
264                 if ($instance->password !== $password) {
265                     $checkpassword = true;
266                 }
267             }
268         } else {
269             if ($data['enrol_guest_status_'.$i] == ENROL_INSTANCE_ENABLED) {
270                 $checkpassword = true;
271             }
272         }
274         if ($checkpassword) {
275             $require = $this->get_config('requirepassword');
276             $policy  = $this->get_config('usepasswordpolicy');
277             if ($require and empty($password)) {
278                 $errors['enrol_guest_password_'.$i] = get_string('required');
279             } else if ($policy) {
280                 $errmsg = '';//prevent eclipse warning
281                 if (!check_password_policy($password, $errmsg)) {
282                     $errors['enrol_guest_password_'.$i] = $errmsg;
283                 }
284             }
285         }
287         return $errors;
288     }
290     /**
291      * Called after updating/inserting course.
292      *
293      * @param bool $inserted true if course just inserted
294      * @param object $course
295      * @param object $data form data
296      * @return void
297      */
298     public function course_updated($inserted, $course, $data) {
299         global $DB;
301         if ($inserted) {
302             if (isset($data->enrol_guest_status_0)) {
303                 $fields = array('status'=>$data->enrol_guest_status_0);
304                 if ($fields['status'] == ENROL_INSTANCE_ENABLED) {
305                     $fields['password'] = $data->enrol_guest_password_0;
306                 } else {
307                     if ($this->get_config('requirepassword')) {
308                         $fields['password'] = generate_password(20);
309                     }
310                 }
311                 $this->add_instance($course, $fields);
312             } else {
313                 if ($this->get_config('defaultenrol')) {
314                     $this->add_default_instance($course);
315                 }
316             }
318         } else {
319             $instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'guest'));
320             foreach ($instances as $instance) {
321                 $i = $instance->id;
323                 if (isset($data->{'enrol_guest_status_'.$i})) {
324                     $reset = ($instance->status != $data->{'enrol_guest_status_'.$i});
326                     $instance->status       = $data->{'enrol_guest_status_'.$i};
327                     $instance->timemodified = time();
328                     if ($instance->status == ENROL_INSTANCE_ENABLED) {
329                         if ($instance->password !== $data->{'enrol_guest_password_'.$i}) {
330                             $reset = true;
331                         }
332                         $instance->password = $data->{'enrol_guest_password_'.$i};
333                     }
334                     $DB->update_record('enrol', $instance);
335                     \core\event\enrol_instance_updated::create_from_record($instance)->trigger();
337                     if ($reset) {
338                         $context = context_course::instance($course->id);
339                         $context->mark_dirty();
340                     }
341                 }
342             }
343         }
344     }
346     /**
347      * Add new instance of enrol plugin.
348      * @param object $course
349      * @param array instance fields
350      * @return int id of new instance, null if can not be created
351      */
352     public function add_instance($course, array $fields = NULL) {
353         $fields = (array)$fields;
355         if (!isset($fields['password'])) {
356             $fields['password'] = '';
357         }
359         return parent::add_instance($course, $fields);
360     }
362     /**
363      * Add new instance of enrol plugin with default settings.
364      * @param object $course
365      * @return int id of new instance
366      */
367     public function add_default_instance($course) {
368         $fields = array('status'=>$this->get_config('status'));
370         if ($this->get_config('requirepassword')) {
371             $fields['password'] = generate_password(20);
372         }
374         return $this->add_instance($course, $fields);
375     }
377     /**
378      * Restore instance and map settings.
379      *
380      * @param restore_enrolments_structure_step $step
381      * @param stdClass $data
382      * @param stdClass $course
383      * @param int $oldid
384      */
385     public function restore_instance(restore_enrolments_structure_step $step, stdClass $data, $course, $oldid) {
386         global $DB;
388         if (!$DB->record_exists('enrol', array('courseid' => $data->courseid, 'enrol' => $this->get_name()))) {
389             $this->add_instance($course, (array)$data);
390         }
392         // No need to set mapping, we do not restore users or roles here.
393         $step->set_mapping('enrol', $oldid, 0);
394     }
396     /**
397      * Is it possible to delete enrol instance via standard UI?
398      *
399      * @param object $instance
400      * @return bool
401      */
402     public function can_delete_instance($instance) {
403         $context = context_course::instance($instance->courseid);
404         return has_capability('enrol/guest:config', $context);
405     }
407     /**
408      * Is it possible to hide/show enrol instance via standard UI?
409      *
410      * @param stdClass $instance
411      * @return bool
412      */
413     public function can_hide_show_instance($instance) {
414         $context = context_course::instance($instance->courseid);
415         return has_capability('enrol/guest:config', $context);
416     }