commit 0be340d91a41fe1fe760706d872446382867fe68 Author: Sesostris Vieira Date: Thu Feb 13 17:31:21 2014 -0200 Plugin de matrĂ­cula para os cursos de EAD diff --git a/cli/sync.php b/cli/sync.php new file mode 100644 index 0000000..2a8dd85 --- /dev/null +++ b/cli/sync.php @@ -0,0 +1,73 @@ +. + +/** + * CLI update for self ilb ead enrolments, use for debugging or immediate update + * of all courses. + * + * Notes: + * - it is required to use the web server account when executing PHP CLI scripts + * - you need to change the "www-data" to match the apache user account + * - use "su" if "sudo" not available + * + * @package enrol_ilbead + * @copyright 2012 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define('CLI_SCRIPT', true); + +require(__DIR__.'/../../../config.php'); +require_once("$CFG->libdir/clilib.php"); + +// Now get cli options. +list($options, $unrecognized) = cli_get_params(array('verbose'=>false, 'help'=>false), array('v'=>'verbose', 'h'=>'help')); + +if ($unrecognized) { + $unrecognized = implode("\n ", $unrecognized); + cli_error(get_string('cliunknowoption', 'admin', $unrecognized)); +} + +if ($options['help']) { + echo "Execute self ilb ead course enrol updates. + +Options: +-v, --verbose Print verbose progress information +-h, --help Print out this help + +Example: +\$ sudo -u www-data /usr/bin/php enrol/ilbead/cli/sync.php +"; + die; +} + +if (!enrol_is_enabled('ilbead')) { + cli_error('enrol_ilbead plugin is disabled, synchronisation stopped', 2); +} + +if (empty($options['verbose'])) { + $trace = new null_progress_trace(); +} else { + $trace = new text_progress_trace(); +} + +/** @var $plugin enrol_ilbead_plugin */ +$plugin = enrol_get_plugin('ilbead'); + +$result = $plugin->sync($trace, null); +$plugin->send_expiry_notifications($trace); + +exit($result); diff --git a/db/access.php b/db/access.php new file mode 100644 index 0000000..289666f --- /dev/null +++ b/db/access.php @@ -0,0 +1,70 @@ +. + +/** + * Capabilities for self ilb ead enrolment plugin. + * + * @package enrol_ilbead + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = array( + + /* Add or edit enrol-ilbead instance in course. */ + 'enrol/ilbead:config' => array( + + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + ) + ), + + /* Manage user ilb ead self-enrolments. */ + 'enrol/ilbead:manage' => array( + + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + ) + ), + + /* Voluntarily unenrol self from ilb ead course - watch out for data loss. */ + 'enrol/ilbead:unenrolself' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'student' => CAP_ALLOW, + ) + ), + + /* Unenrol anybody from course (including self) - watch out for data loss. */ + 'enrol/ilbead:unenrol' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + ) + ), + +); diff --git a/db/install.php b/db/install.php new file mode 100644 index 0000000..b7303c2 --- /dev/null +++ b/db/install.php @@ -0,0 +1,29 @@ +. + +/** + * Self enrol plugin installation script + * + * @package enrol_ilbead + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die(); + +function xmldb_enrol_ilbead_install() { + global $CFG, $DB; + +} diff --git a/db/messages.php b/db/messages.php new file mode 100644 index 0000000..d1ebc90 --- /dev/null +++ b/db/messages.php @@ -0,0 +1,29 @@ +. + +/** + * Defines message providers for self ilb ead enrolments. + * + * @package enrol_ilbead + * @copyright 2012 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$messageproviders = array ( + + 'expiry_notification' => array(), + +); diff --git a/db/upgrade.php b/db/upgrade.php new file mode 100644 index 0000000..4b41a92 --- /dev/null +++ b/db/upgrade.php @@ -0,0 +1,64 @@ +. + +/** + * This file keeps track of upgrades to the self ilb ead enrolment plugin + * + * @package enrol_ilbead + * @copyright 2012 Petr Skoda {@link http://skodak.org + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +function xmldb_enrol_ilbead_upgrade($oldversion) { + global $CFG, $DB, $OUTPUT; + + $dbman = $DB->get_manager(); + + // Moodle v2.3.0 release upgrade line + // Put any upgrade step following this + + if ($oldversion < 2012101400) { + // Set default expiry threshold to 1 day. + $DB->execute("UPDATE {enrol} SET expirythreshold = 86400 WHERE enrol = 'ilbead' AND expirythreshold = 0"); + upgrade_plugin_savepoint(true, 2012101400, 'enrol', 'ilbead'); + } + + if ($oldversion < 2012120600) { + // Enable new self ilb ead enrolments everywhere. + $DB->execute("UPDATE {enrol} SET customint6 = 1 WHERE enrol = 'ilbead'"); + upgrade_plugin_savepoint(true, 2012120600, 'enrol', 'ilbead'); + } + + + // Moodle v2.4.0 release upgrade line + // Put any upgrade step following this + + + // Moodle v2.5.0 release upgrade line. + // Put any upgrade step following this. + if ($oldversion < 2013050101) { + // Set customint1 (group enrolment key) to 0 if it was not set (null). + $DB->execute("UPDATE {enrol} SET customint1 = 0 WHERE enrol = 'ilbead' AND customint1 IS NULL"); + upgrade_plugin_savepoint(true, 2013050101, 'enrol', 'ilbead'); + } + + + return true; +} + + diff --git a/edit.php b/edit.php new file mode 100644 index 0000000..bd05687 --- /dev/null +++ b/edit.php @@ -0,0 +1,152 @@ +. + +/** + * Adds new instance of enrol_ilbead to specified course + * or edits current instance. + * + * @package enrol_ilbead + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../config.php'); +require_once('edit_form.php'); + +$courseid = required_param('courseid', PARAM_INT); +$instanceid = optional_param('id', 0, PARAM_INT); + +$course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST); +$context = context_course::instance($course->id, MUST_EXIST); + +require_login($course); +require_capability('enrol/ilbead:config', $context); + +$PAGE->set_url('/enrol/ilbead/edit.php', array('courseid'=>$course->id, 'id'=>$instanceid)); +$PAGE->set_pagelayout('admin'); + +$return = new moodle_url('/enrol/instances.php', array('id'=>$course->id)); +if (!enrol_is_enabled('ilbead')) { + redirect($return); +} + +/** @var enrol_ilbead_plugin $plugin */ +$plugin = enrol_get_plugin('ilbead'); + +if ($instanceid) { + $instance = $DB->get_record('enrol', array('courseid'=>$course->id, 'enrol'=>'ilbead', 'id'=>$instanceid), '*', MUST_EXIST); + +} else { + require_capability('moodle/course:enrolconfig', $context); + // No instance yet, we have to add new instance. + navigation_node::override_active_url(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); + + $instance = (object)$plugin->get_instance_defaults(); + $instance->id = null; + $instance->courseid = $course->id; + $instance->status = ENROL_INSTANCE_ENABLED; // Do not use default for automatically created instances here. +} + +// Merge these two settings to one value for the single selection element. +if ($instance->notifyall and $instance->expirynotify) { + $instance->expirynotify = 2; +} +unset($instance->notifyall); + +$mform = new enrol_ilbead_edit_form(NULL, array($instance, $plugin, $context)); + +if ($mform->is_cancelled()) { + redirect($return); + +} else if ($data = $mform->get_data()) { + if ($data->expirynotify == 2) { + $data->expirynotify = 1; + $data->notifyall = 1; + } else { + $data->notifyall = 0; + } + if (!$data->expirynotify) { + // Keep previous/default value of disabled expirythreshold option. + $data->expirythreshold = $instance->expirythreshold; + } + if (!isset($data->customint6)) { + // Add previous value of newenrols if disabled. + $data->customint6 = $instance->customint6; + } + + if ($instance->id) { + $reset = ($instance->status != $data->status); + + $instance->status = $data->status; + $instance->name = $data->name; + $instance->password = $data->password; + $instance->customint1 = $data->customint1; + $instance->customint2 = $data->customint2; + $instance->customint3 = $data->customint3; + $instance->customint4 = $data->customint4; + $instance->customint5 = $data->customint5; + $instance->customint6 = $data->customint6; + $instance->customint7 = $data->customint7; + $instance->customint8 = $data->customint8; + $instance->customtext1 = $data->customtext1; + $instance->roleid = $data->roleid; + $instance->enrolperiod = $data->enrolperiod; + $instance->expirynotify = $data->expirynotify; + $instance->notifyall = $data->notifyall; + $instance->expirythreshold = $data->expirythreshold; + $instance->enrolstartdate = $data->enrolstartdate; + $instance->enrolenddate = $data->enrolenddate; + $instance->timemodified = time(); + $DB->update_record('enrol', $instance); + + if ($reset) { + $context->mark_dirty(); + } + + } else { + $fields = array( + 'status' => $data->status, + 'name' => $data->name, + 'password' => $data->password, + 'customint1' => $data->customint1, + 'customint2' => $data->customint2, + 'customint3' => $data->customint3, + 'customint4' => $data->customint4, + 'customint5' => $data->customint5, + 'customint6' => $data->customint6, + 'customint7' => $data->customint7, + 'customint8' => $data->customint8, + 'customtext1' => $data->customtext1, + 'roleid' => $data->roleid, + 'enrolperiod' => $data->enrolperiod, + 'expirynotify' => $data->expirynotify, + 'notifyall' => $data->notifyall, + 'expirythreshold' => $data->expirythreshold, + 'enrolstartdate' => $data->enrolstartdate, + 'enrolenddate' => $data->enrolenddate); + $plugin->add_instance($course, $fields); + } + + redirect($return); +} + +$PAGE->set_heading($course->fullname); +$PAGE->set_title(get_string('pluginname', 'enrol_ilbead')); + +echo $OUTPUT->header(); +echo $OUTPUT->heading(get_string('pluginname', 'enrol_ilbead')); +$mform->display(); +echo $OUTPUT->footer(); diff --git a/edit_form.php b/edit_form.php new file mode 100644 index 0000000..46dced0 --- /dev/null +++ b/edit_form.php @@ -0,0 +1,226 @@ +. + +/** + * Adds new instance of enrol_ilbead to specified course + * or edits current instance. + * + * @package enrol_ilbead + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->libdir.'/formslib.php'); + +class enrol_ilbead_edit_form extends moodleform { + + function definition() { + global $DB; + + $mform = $this->_form; + + list($instance, $plugin, $context) = $this->_customdata; + + $mform->addElement('header', 'header', get_string('pluginname', 'enrol_ilbead')); + + $mform->addElement('text', 'name', get_string('custominstancename', 'enrol')); + $mform->setType('name', PARAM_TEXT); + + $options = array(ENROL_INSTANCE_ENABLED => get_string('yes'), + ENROL_INSTANCE_DISABLED => get_string('no')); + $mform->addElement('select', 'status', get_string('status', 'enrol_ilbead'), $options); + $mform->addHelpButton('status', 'status', 'enrol_ilbead'); + + $options = array(1 => get_string('yes'), 0 => get_string('no')); + $mform->addElement('select', 'customint6', get_string('newenrols', 'enrol_ilbead'), $options); + $mform->addHelpButton('customint6', 'newenrols', 'enrol_ilbead'); + $mform->disabledIf('customint6', 'status', 'eq', ENROL_INSTANCE_DISABLED); + + $mform->addElement('passwordunmask', 'password', get_string('password', 'enrol_ilbead')); + $mform->addHelpButton('password', 'password', 'enrol_ilbead'); + if (empty($instance->id) and $plugin->get_config('requirepassword')) { + $mform->addRule('password', get_string('required'), 'required', null, 'client'); + } + + $options = array(1 => get_string('yes'), + 0 => get_string('no')); + $mform->addElement('select', 'customint1', get_string('groupkey', 'enrol_ilbead'), $options); + $mform->addHelpButton('customint1', 'groupkey', 'enrol_ilbead'); + + $roles = $this->extend_assignable_roles($context, $instance->roleid); + $mform->addElement('select', 'roleid', get_string('role', 'enrol_ilbead'), $roles); + + $mform->addElement('duration', 'enrolperiod', get_string('enrolperiod', 'enrol_ilbead'), array('optional' => true, 'defaultunit' => 86400)); + $mform->addHelpButton('enrolperiod', 'enrolperiod', 'enrol_ilbead'); + + $options = array(0 => get_string('no'), 1 => get_string('expirynotifyenroller', 'core_enrol'), 2 => get_string('expirynotifyall', 'core_enrol')); + $mform->addElement('select', 'expirynotify', get_string('expirynotify', 'core_enrol'), $options); + $mform->addHelpButton('expirynotify', 'expirynotify', 'core_enrol'); + + $mform->addElement('duration', 'expirythreshold', get_string('expirythreshold', 'core_enrol'), array('optional' => false, 'defaultunit' => 86400)); + $mform->addHelpButton('expirythreshold', 'expirythreshold', 'core_enrol'); + $mform->disabledIf('expirythreshold', 'expirynotify', 'eq', 0); + + $mform->addElement('date_selector', 'enrolstartdate', get_string('enrolstartdate', 'enrol_ilbead'), array('optional' => true)); + $mform->setDefault('enrolstartdate', 0); + $mform->addHelpButton('enrolstartdate', 'enrolstartdate', 'enrol_ilbead'); + + $mform->addElement('date_selector', 'enrolenddate', get_string('enrolenddate', 'enrol_ilbead'), array('optional' => true)); + $mform->setDefault('enrolenddate', 0); + $mform->addHelpButton('enrolenddate', 'enrolenddate', 'enrol_ilbead'); + + $options = array(0 => get_string('never'), + 1800 * 3600 * 24 => get_string('numdays', '', 1800), + 1000 * 3600 * 24 => get_string('numdays', '', 1000), + 365 * 3600 * 24 => get_string('numdays', '', 365), + 180 * 3600 * 24 => get_string('numdays', '', 180), + 150 * 3600 * 24 => get_string('numdays', '', 150), + 120 * 3600 * 24 => get_string('numdays', '', 120), + 90 * 3600 * 24 => get_string('numdays', '', 90), + 60 * 3600 * 24 => get_string('numdays', '', 60), + 30 * 3600 * 24 => get_string('numdays', '', 30), + 21 * 3600 * 24 => get_string('numdays', '', 21), + 14 * 3600 * 24 => get_string('numdays', '', 14), + 7 * 3600 * 24 => get_string('numdays', '', 7)); + $mform->addElement('select', 'customint2', get_string('longtimenosee', 'enrol_ilbead'), $options); + $mform->addHelpButton('customint2', 'longtimenosee', 'enrol_ilbead'); + + $mform->addElement('text', 'customint3', get_string('maxenrolled', 'enrol_ilbead')); + $mform->addHelpButton('customint3', 'maxenrolled', 'enrol_ilbead'); + $mform->setType('customint3', PARAM_INT); + + $mform->addElement('text', 'customint7', get_string('maxongoing', 'enrol_ilbead')); + $mform->addHelpButton('customint7', 'maxongoing', 'enrol_ilbead'); + $mform->setType('customint7', PARAM_INT); + + $mform->addElement('text', 'customint8', get_string('abandonpunishment', 'enrol_ilbead')); + $mform->addHelpButton('customint8', 'abandonpunishment', 'enrol_ilbead'); + $mform->setType('customint8', PARAM_INT); + + $cohorts = array(0 => get_string('no')); + list($sqlparents, $params) = $DB->get_in_or_equal($context->get_parent_context_ids(), SQL_PARAMS_NAMED); + $params['current'] = $instance->customint5; + $sql = "SELECT id, name, idnumber, contextid + FROM {cohort} + WHERE contextid $sqlparents OR id = :current + ORDER BY name ASC, idnumber ASC"; + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $c) { + $ccontext = context::instance_by_id($c->contextid); + if ($c->id != $instance->customint5 and !has_capability('moodle/cohort:view', $ccontext)) { + continue; + } + $cohorts[$c->id] = format_string($c->name, true, array('context'=>$context)); + if ($c->idnumber) { + $cohorts[$c->id] .= ' ['.s($c->idnumber).']'; + } + } + if (!isset($cohorts[$instance->customint5])) { + // Somebody deleted a cohort, better keep the wrong value so that random ppl can not enrol. + $cohorts[$instance->customint5] = get_string('unknowncohort', 'cohort', $instance->customint5); + } + $rs->close(); + if (count($cohorts) > 1) { + $mform->addElement('select', 'customint5', get_string('cohortonly', 'enrol_ilbead'), $cohorts); + $mform->addHelpButton('customint5', 'cohortonly', 'enrol_ilbead'); + } else { + $mform->addElement('hidden', 'customint5'); + $mform->setType('customint5', PARAM_INT); + $mform->setConstant('customint5', 0); + } + + $mform->addElement('advcheckbox', 'customint4', get_string('sendcoursewelcomemessage', 'enrol_ilbead')); + $mform->addHelpButton('customint4', 'sendcoursewelcomemessage', 'enrol_ilbead'); + + $mform->addElement('textarea', 'customtext1', get_string('customwelcomemessage', 'enrol_ilbead'), array('cols'=>'60', 'rows'=>'8')); + $mform->addHelpButton('customtext1', 'customwelcomemessage', 'enrol_ilbead'); + + $mform->addElement('hidden', 'id'); + $mform->setType('id', PARAM_INT); + $mform->addElement('hidden', 'courseid'); + $mform->setType('courseid', PARAM_INT); + + $this->add_action_buttons(true, ($instance->id ? null : get_string('addinstance', 'enrol'))); + + $this->set_data($instance); + } + + function validation($data, $files) { + global $DB, $CFG; + $errors = parent::validation($data, $files); + + list($instance, $plugin, $context) = $this->_customdata; + $checkpassword = false; + + if ($instance->id) { + if ($data['status'] == ENROL_INSTANCE_ENABLED) { + if ($instance->password !== $data['password']) { + $checkpassword = true; + } + } + } else { + if ($data['status'] == ENROL_INSTANCE_ENABLED) { + $checkpassword = true; + } + } + + if ($checkpassword) { + $require = $plugin->get_config('requirepassword'); + $policy = $plugin->get_config('usepasswordpolicy'); + if ($require and trim($data['password']) === '') { + $errors['password'] = get_string('required'); + } else if ($policy) { + $errmsg = '';//prevent eclipse warning + if (!check_password_policy($data['password'], $errmsg)) { + $errors['password'] = $errmsg; + } + } + } + + if ($data['status'] == ENROL_INSTANCE_ENABLED) { + if (!empty($data['enrolenddate']) and $data['enrolenddate'] < $data['enrolstartdate']) { + $errors['enrolenddate'] = get_string('enrolenddaterror', 'enrol_ilbead'); + } + } + + if ($data['expirynotify'] > 0 and $data['expirythreshold'] < 86400) { + $errors['expirythreshold'] = get_string('errorthresholdlow', 'core_enrol'); + } + + return $errors; + } + + /** + * Gets a list of roles that this user can assign for the course as the default for ilb ead self-enrolment. + * + * @param context $context the context. + * @param integer $defaultrole the id of the role that is set as the default for ilb ead self-enrolment + * @return array index is the role id, value is the role name + */ + function extend_assignable_roles($context, $defaultrole) { + global $DB; + + $roles = get_assignable_roles($context, ROLENAME_BOTH); + if (!isset($roles[$defaultrole])) { + if ($role = $DB->get_record('role', array('id'=>$defaultrole))) { + $roles[$defaultrole] = role_get_name($role, $context, ROLENAME_BOTH); + } + } + return $roles; + } +} diff --git a/lang/en/enrol_ilbead.php b/lang/en/enrol_ilbead.php new file mode 100644 index 0000000..9a08f5c --- /dev/null +++ b/lang/en/enrol_ilbead.php @@ -0,0 +1,121 @@ +. + +/** + * Strings for component 'enrol_ilbead', language 'en'. + * + * @package enrol_ilbead + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['cohortnonmemberinfo'] = 'Only members of cohort \'{$a}\' can self-enrol.'; +$string['cohortonly'] = 'Only cohort members'; +$string['cohortonly_help'] = 'Self enrolment may be restricted to members of a specified cohort only. Note that changing this setting has no effect on existing enrolments.'; +$string['customwelcomemessage'] = 'Custom welcome message'; +$string['customwelcomemessage_help'] = 'A custom welcome message may be added as plain text or Moodle-auto format, including HTML tags and multi-lang tags. + +The following placeholders may be included in the message: + +* Course name {$a->coursename} +* Link to user\'s profile page {$a->profileurl}'; +$string['defaultrole'] = 'Default role assignment'; +$string['defaultrole_desc'] = 'Select role which should be assigned to users during self enrolment'; +$string['enrolenddate'] = 'End date'; +$string['enrolenddate_help'] = 'If enabled, users can enrol themselves until this date only.'; +$string['enrolenddaterror'] = 'Enrolment end date cannot be earlier than start date'; +$string['enrolme'] = 'Enrol me'; +$string['enrolperiod'] = 'Enrolment duration'; +$string['enrolperiod_desc'] = 'Default length of time that the enrolment is valid. If set to zero, the enrolment duration will be unlimited by default.'; +$string['enrolperiod_help'] = 'Length of time that the enrolment is valid, starting with the moment the user enrols themselves. If disabled, the enrolment duration will be unlimited.'; +$string['enrolstartdate'] = 'Start date'; +$string['enrolstartdate_help'] = 'If enabled, users can enrol themselves from this date onward only.'; +$string['expiredaction'] = 'Enrolment expiration action'; +$string['expiredaction_help'] = 'Select action to carry out when user enrolment expires. Please note that some user data and settings are purged from course during course unenrolment.'; +$string['expirymessageenrollersubject'] = 'Self enrolment expiry notification'; +$string['expirymessageenrollerbody'] = 'Self enrolment in the course \'{$a->course}\' will expire within the next {$a->threshold} for the following users: + +{$a->users} + +To extend their enrolment, go to {$a->extendurl}'; +$string['expirymessageenrolledsubject'] = 'Self enrolment expiry notification'; +$string['expirymessageenrolledbody'] = 'Dear {$a->user}, + +This is a notification that your enrolment in the course \'{$a->course}\' is due to expire on {$a->timeend}. + +If you need help, please contact {$a->enroller}.'; +$string['groupkey'] = 'Use group enrolment keys'; +$string['groupkey_desc'] = 'Use group enrolment keys by default.'; +$string['groupkey_help'] = 'In addition to restricting access to the course to only those who know the key, use of group enrolment keys means users are automatically added to groups when they enrol in the course. + +Note: An enrolment key for the course must be specified in the self enrolment settings as well as group enrolment keys in the group settings.'; +$string['longtimenosee'] = 'Unenrol inactive after'; +$string['longtimenosee_help'] = 'If users haven\'t accessed a course for a long time, then they are automatically unenrolled. This parameter specifies that time limit.'; +$string['maxenrolled'] = 'Max enrolled users'; +$string['maxenrolled_help'] = 'Specifies the maximum number of users that can self enrol. 0 means no limit.'; +$string['maxenrolledreached'] = 'Maximum number of users allowed to self-enrol was already reached.'; +$string['messageprovider:expiry_notification'] = 'Self enrolment expiry notifications'; +$string['newenrols'] = 'Allow new enrolments'; +$string['newenrols_desc'] = 'Allow users to self enrol into new ilb ead courses by default.'; +$string['newenrols_help'] = 'This setting determines whether a user can enrol into this course.'; +$string['nopassword'] = 'No enrolment key required.'; +$string['password'] = 'Enrolment key'; +$string['password_help'] = 'An enrolment key enables access to the course to be restricted to only those who know the key. + +If the field is left blank, any user may enrol in the course. + +If an enrolment key is specified, any user attempting to enrol in the course will be required to supply the key. Note that a user only needs to supply the enrolment key ONCE, when they enrol in the course.'; +$string['passwordinvalid'] = 'Incorrect enrolment key, please try again'; +$string['passwordinvalidhint'] = 'That enrolment key was incorrect, please try again
+(Here\'s a hint - it starts with \'{$a}\')'; +$string['pluginname'] = 'ILB/EAD self enrolment'; +$string['pluginname_desc'] = 'The ilbead enrolment plugin allows users to choose which courses they want to participate in. The courses may be protected by an enrolment key. Internally the enrolment is done via the manual enrolment plugin which has to be enabled in the same course.'; +$string['requirepassword'] = 'Require enrolment key'; +$string['requirepassword_desc'] = 'Require enrolment key in new courses and prevent removing of enrolment key from existing courses.'; +$string['role'] = 'Default assigned role'; +$string['ilbead:config'] = 'Configure ILB EAD self enrol instances'; +$string['ilbead:manage'] = 'Manage enrolled users'; +$string['ilbead:unenrol'] = 'Unenrol users from course'; +$string['ilbead:unenrolilbead'] = 'Unenrol self from the course'; +$string['sendcoursewelcomemessage'] = 'Send course welcome message'; +$string['sendcoursewelcomemessage_help'] = 'If enabled, users receive a welcome message via email when they self-enrol in a course.'; +$string['showhint'] = 'Show hint'; +$string['showhint_desc'] = 'Show first letter of the guest access key.'; +$string['status'] = 'Enable existing enrolments'; +$string['status_desc'] = 'Enable ilb ead self enrolment method in new courses.'; +$string['status_help'] = 'If disabled all existing self enrolments are suspended and new users can not enrol.'; +$string['unenrol'] = 'Unenrol user'; +$string['unenrolilbeadconfirm'] = 'Do you really want to unenrol yourself from course "{$a}"?'; +$string['unenroluser'] = 'Do you really want to unenrol "{$a->user}" from course "{$a->course}"?'; +$string['usepasswordpolicy'] = 'Use password policy'; +$string['usepasswordpolicy_desc'] = 'Use standard password policy for enrolment keys.'; +$string['welcometocourse'] = 'Welcome to {$a}'; +$string['welcometocoursetext'] = 'Welcome to {$a->coursename}! + +If you have not done so already, you should edit your profile page so that we can learn more about you: + + {$a->profileurl}'; +$string['maxongoing'] = 'Max ongoing ILB EAD courses'; +$string['ongoingcourses'] = 'List of ongoing courses'; +$string['abandonedcourses'] = 'Abandoned courses'; +$string['enrolledat'] = 'enrolled at'; +$string['abandonalert'] = 'You have abandoned courses and cannot enroll in new courses.'; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; diff --git a/lib.php b/lib.php new file mode 100644 index 0000000..3ab3033 --- /dev/null +++ b/lib.php @@ -0,0 +1,683 @@ +. + +/** + * Self enrolment plugin. + * + * @package enrol_ilbead + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Self enrolment plugin implementation. + * @author Petr Skoda + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_ilbead_plugin extends enrol_plugin { + + protected $lasternoller = null; + protected $lasternollerinstanceid = 0; + + /** + * Returns optional enrolment information icons. + * + * This is used in course list for quick overview of enrolment options. + * + * We are not using single instance parameter because sometimes + * we might want to prevent icon repetition when multiple instances + * of one type exist. One instance may also produce several icons. + * + * @param array $instances all enrol instances of this type in one course + * @return array of pix_icon + */ + public function get_info_icons(array $instances) { + $key = false; + $nokey = false; + foreach ($instances as $instance) { + if (!$instance->customint6) { + // New enrols not allowed. + continue; + } + if ($instance->password or $instance->customint1) { + $key = true; + } else { + $nokey = true; + } + } + $icons = array(); + if ($nokey) { + $icons[] = new pix_icon('withoutkey', get_string('pluginname', 'enrol_ilbead'), 'enrol_ilbead'); + } + if ($key) { + $icons[] = new pix_icon('withkey', get_string('pluginname', 'enrol_ilbead'), 'enrol_ilbead'); + } + return $icons; + } + + /** + * Returns localised name of enrol instance + * + * @param stdClass $instance (null is accepted too) + * @return string + */ + public function get_instance_name($instance) { + global $DB; + + if (empty($instance->name)) { + if (!empty($instance->roleid) and $role = $DB->get_record('role', array('id'=>$instance->roleid))) { + $role = ' (' . role_get_name($role, context_course::instance($instance->courseid, IGNORE_MISSING)) . ')'; + } else { + $role = ''; + } + $enrol = $this->get_name(); + return get_string('pluginname', 'enrol_'.$enrol) . $role; + } else { + return format_string($instance->name); + } + } + + public function roles_protected() { + // Users may tweak the roles later. + return false; + } + + public function allow_unenrol(stdClass $instance) { + // Users with unenrol cap may unenrol other users manually manually. + return true; + } + + public function allow_manage(stdClass $instance) { + // Users with manage cap may tweak period and status. + return true; + } + + public function show_enrolme_link(stdClass $instance) { + global $CFG, $USER; + + if ($instance->status != ENROL_INSTANCE_ENABLED) { + return false; + } + + if (!$instance->customint6) { + // New enrols not allowed. + return false; + } + + if ($this->max_ongoing_reached($instance)) { + // Max ongoing EAD courses reached. New enrol not allowed + return false; + } + + if ($instance->customint5) { + require_once("$CFG->dirroot/cohort/lib.php"); + return cohort_is_member($instance->customint5, $USER->id); + } + return true; + } + + /** + * Sets up navigation entries. + * + * @param stdClass $instancesnode + * @param stdClass $instance + * @return void + */ + public function add_course_navigation($instancesnode, stdClass $instance) { + if ($instance->enrol !== 'ilbead') { + throw new coding_exception('Invalid enrol instance type!'); + } + + $context = context_course::instance($instance->courseid); + if (has_capability('enrol/ilbead:config', $context)) { + $managelink = new moodle_url('/enrol/ilbead/edit.php', array('courseid'=>$instance->courseid, 'id'=>$instance->id)); + $instancesnode->add($this->get_instance_name($instance), $managelink, navigation_node::TYPE_SETTING); + } + } + + /** + * Returns edit icons for the page with list of instances + * @param stdClass $instance + * @return array + */ + public function get_action_icons(stdClass $instance) { + global $OUTPUT; + + if ($instance->enrol !== 'ilbead') { + throw new coding_exception('invalid enrol instance!'); + } + $context = context_course::instance($instance->courseid); + + $icons = array(); + + if (has_capability('enrol/ilbead:config', $context)) { + $editlink = new moodle_url("/enrol/ilbead/edit.php", array('courseid'=>$instance->courseid, 'id'=>$instance->id)); + $icons[] = $OUTPUT->action_icon($editlink, new pix_icon('t/edit', get_string('edit'), 'core', + array('class' => 'iconsmall'))); + } + + return $icons; + } + + /** + * Returns link to page which may be used to add new instance of enrolment plugin in course. + * @param int $courseid + * @return moodle_url page url + */ + public function get_newinstance_link($courseid) { + $context = context_course::instance($courseid, MUST_EXIST); + + if (!has_capability('moodle/course:enrolconfig', $context) or !has_capability('enrol/ilbead:config', $context)) { + return NULL; + } + // Multiple instances supported - different roles with different password. + return new moodle_url('/enrol/ilbead/edit.php', array('courseid'=>$courseid)); + } + + /** + * Creates course enrol form, checks if form submitted + * and enrols user if necessary. It can also redirect. + * + * @param stdClass $instance + * @return string html text, usually a form in a text box + */ + public function enrol_page_hook(stdClass $instance) { + global $CFG, $OUTPUT, $SESSION, $USER, $DB; + + if (isguestuser()) { + // Can not enrol guest!! + return null; + } + if ($DB->record_exists('user_enrolments', array('userid'=>$USER->id, 'enrolid'=>$instance->id))) { + //TODO: maybe we should tell them they are already enrolled, but can not access the course + return null; + } + + if ($instance->enrolstartdate != 0 and $instance->enrolstartdate > time()) { + //TODO: inform that we can not enrol yet + return null; + } + + if ($instance->enrolenddate != 0 and $instance->enrolenddate < time()) { + //TODO: inform that enrolment is not possible any more + return null; + } + + if (!$instance->customint6) { + // New enrols not allowed. + return null; + } + + if ($instance->customint7 !== null and $instance->customint7 > 0) { + $ongoing = $this->get_ongoing(); + if (count($ongoing) >= $instance->customint7) { + // Max ongoing EAD courses reached. New enrol not allowed + $s = get_string('maxongoing', 'enrol_ilbead').'

'; + $s .= '' . get_string('ongoingcourses', 'enrol_ilbead') . ':
'; + foreach ($ongoing as $course) { + $s .= "{$course->fullname}
"; + } + return $OUTPUT->box($s); + } + } + + if ($instance->customint8 !== null and $instance->customint8 > 0) { + $abandoned = $this->abandon_courses($instance); + if (count($abandoned) > 0) { + $s = get_string('abandonalert', 'enrol_ilbead').'

'; + $s .= '' . get_string('abandonedcourses', 'enrol_ilbead') . ':
'; + $enrolledat = get_string('enrolledat', 'enrol_ilbead'); + foreach ($abandoned as $course) { + $date = userdate($course->timecreated); + $s .= "{$course->fullname}, $enrolledat $date
"; + } + return $OUTPUT->box($s); + } + } + + if ($instance->customint5) { + require_once("$CFG->dirroot/cohort/lib.php"); + if (!cohort_is_member($instance->customint5, $USER->id)) { + $cohort = $DB->get_record('cohort', array('id'=>$instance->customint5)); + if (!$cohort) { + return null; + } + $a = format_string($cohort->name, true, array('context'=>context::instance_by_id($cohort->contextid))); + return $OUTPUT->box(markdown_to_html(get_string('cohortnonmemberinfo', 'enrol_ilbead', $a))); + } + } + + require_once("$CFG->dirroot/enrol/ilbead/locallib.php"); + require_once("$CFG->dirroot/group/lib.php"); + + $form = new enrol_ilbead_enrol_form(NULL, $instance); + $instanceid = optional_param('instance', 0, PARAM_INT); + + if ($instance->id == $instanceid) { + if ($data = $form->get_data()) { + $enrol = enrol_get_plugin('ilbead'); + $timestart = time(); + if ($instance->enrolperiod) { + $timeend = $timestart + $instance->enrolperiod; + } else { + $timeend = 0; + } + + $this->enrol_user($instance, $USER->id, $instance->roleid, $timestart, $timeend); + add_to_log($instance->courseid, 'course', 'enrol', '../enrol/users.php?id='.$instance->courseid, $instance->courseid); //TODO: There should be userid somewhere! + + if ($instance->password and $instance->customint1 and $data->enrolpassword !== $instance->password) { + // it must be a group enrolment, let's assign group too + $groups = $DB->get_records('groups', array('courseid'=>$instance->courseid), 'id', 'id, enrolmentkey'); + foreach ($groups as $group) { + if (empty($group->enrolmentkey)) { + continue; + } + if ($group->enrolmentkey === $data->enrolpassword) { + groups_add_member($group->id, $USER->id); + break; + } + } + } + // Send welcome message. + if ($instance->customint4) { + $this->email_welcome_message($instance, $USER); + } + } + } + + ob_start(); + $form->display(); + $output = ob_get_clean(); + + return $OUTPUT->box($output); + } + + /** + * Add new instance of enrol plugin with default settings. + * @param stdClass $course + * @return int id of new instance + */ + public function add_default_instance($course) { + $fields = $this->get_instance_defaults(); + + if ($this->get_config('requirepassword')) { + $fields['password'] = generate_password(20); + } + + return $this->add_instance($course, $fields); + } + + /** + * Returns defaults for new instances. + * @return array + */ + public function get_instance_defaults() { + $expirynotify = $this->get_config('expirynotify'); + if ($expirynotify == 2) { + $expirynotify = 1; + $notifyall = 1; + } else { + $notifyall = 0; + } + + $fields = array(); + $fields['status'] = $this->get_config('status'); + $fields['roleid'] = $this->get_config('roleid'); + $fields['enrolperiod'] = $this->get_config('enrolperiod'); + $fields['expirynotify'] = $expirynotify; + $fields['notifyall'] = $notifyall; + $fields['expirythreshold'] = $this->get_config('expirythreshold'); + $fields['customint1'] = $this->get_config('groupkey'); + $fields['customint2'] = $this->get_config('longtimenosee'); + $fields['customint3'] = $this->get_config('maxenrolled'); + $fields['customint4'] = $this->get_config('sendcoursewelcomemessage'); + $fields['customint5'] = 0; + $fields['customint6'] = $this->get_config('newenrols'); + $fields['customint7'] = $this->get_config('maxongoing'); + $fields['customint8'] = $this->get_config('abandonpunishment'); + + return $fields; + } + + /** + * Send welcome email to specified user. + * + * @param stdClass $instance + * @param stdClass $user user record + * @return void + */ + protected function email_welcome_message($instance, $user) { + global $CFG, $DB; + + $course = $DB->get_record('course', array('id'=>$instance->courseid), '*', MUST_EXIST); + $context = context_course::instance($course->id); + + $a = new stdClass(); + $a->coursename = format_string($course->fullname, true, array('context'=>$context)); + $a->profileurl = "$CFG->wwwroot/user/view.php?id=$user->id&course=$course->id"; + + if (trim($instance->customtext1) !== '') { + $message = $instance->customtext1; + $message = str_replace('{$a->coursename}', $a->coursename, $message); + $message = str_replace('{$a->profileurl}', $a->profileurl, $message); + if (strpos($message, '<') === false) { + // Plain text only. + $messagetext = $message; + $messagehtml = text_to_html($messagetext, null, false, true); + } else { + // This is most probably the tag/newline soup known as FORMAT_MOODLE. + $messagehtml = format_text($message, FORMAT_MOODLE, array('context'=>$context, 'para'=>false, 'newlines'=>true, 'filter'=>true)); + $messagetext = html_to_text($messagehtml); + } + } else { + $messagetext = get_string('welcometocoursetext', 'enrol_ilbead', $a); + $messagehtml = text_to_html($messagetext, null, false, true); + } + + $subject = get_string('welcometocourse', 'enrol_ilbead', format_string($course->fullname, true, array('context'=>$context))); + + $rusers = array(); + if (!empty($CFG->coursecontact)) { + $croles = explode(',', $CFG->coursecontact); + list($sort, $sortparams) = users_order_by_sql('u'); + $rusers = get_role_users($croles, $context, true, '', 'r.sortorder ASC, ' . $sort, null, '', '', '', '', $sortparams); + } + if ($rusers) { + $contact = reset($rusers); + } else { + $contact = generate_email_supportuser(); + } + + // Directly emailing welcome message rather than using messaging. + email_to_user($user, $contact, $subject, $messagetext, $messagehtml); + } + + /** + * Enrol ilbead cron support. + * @return void + */ + public function cron() { + $trace = new text_progress_trace(); + $this->sync($trace, null); + $this->send_expiry_notifications($trace); + } + + /** + * Sync all meta course links. + * + * @param progress_trace $trace + * @param int $courseid one course, empty mean all + * @return int 0 means ok, 1 means error, 2 means plugin disabled + */ + public function sync(progress_trace $trace, $courseid = null) { + global $DB; + + if (!enrol_is_enabled('ilbead')) { + $trace->finished(); + return 2; + } + + // Unfortunately this may take a long time, execution can be interrupted safely here. + @set_time_limit(0); + raise_memory_limit(MEMORY_HUGE); + + $trace->output('Verifying ilb ead self-enrolments...'); + + $params = array('now'=>time(), 'useractive'=>ENROL_USER_ACTIVE, 'courselevel'=>CONTEXT_COURSE); + $coursesql = ""; + if ($courseid) { + $coursesql = "AND e.courseid = :courseid"; + $params['courseid'] = $courseid; + } + + // Note: the logic of ilb ead self enrolment guarantees that user logged in at least once (=== u.lastaccess set) + // and that user accessed course at least once too (=== user_lastaccess record exists). + + // First deal with users that did not log in for a really long time - they do not have user_lastaccess records. + $sql = "SELECT e.*, ue.userid + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'ilbead' AND e.customint2 > 0) + JOIN {user} u ON u.id = ue.userid + WHERE :now - u.lastaccess > e.customint2 + $coursesql"; + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $instance) { + $userid = $instance->userid; + unset($instance->userid); + $this->unenrol_user($instance, $userid); + $days = $instance->customint2 / 60*60*24; + $trace->output("unenrolling user $userid from course $instance->courseid as they have did not log in for at least $days days", 1); + } + $rs->close(); + + // Now unenrol from course user did not visit for a long time. + $sql = "SELECT e.*, ue.userid + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'ilbead' AND e.customint2 > 0) + JOIN {user_lastaccess} ul ON (ul.userid = ue.userid AND ul.courseid = e.courseid) + WHERE :now - ul.timeaccess > e.customint2 + $coursesql"; + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $instance) { + $userid = $instance->userid; + unset($instance->userid); + $this->unenrol_user($instance, $userid); + $days = $instance->customint2 / 60*60*24; + $trace->output("unenrolling user $userid from course $instance->courseid as they have did not access course for at least $days days", 1); + } + $rs->close(); + + $trace->output('...user ilb ead self-enrolment updates finished.'); + $trace->finished(); + + $this->process_expirations($trace, $courseid); + + return 0; + } + + /** + * Returns the user who is responsible for ilb ead self enrolments in given instance. + * + * Usually it is the first editing teacher - the person with "highest authority" + * as defined by sort_by_roleassignment_authority() having 'enrol/ilbead:manage' + * capability. + * + * @param int $instanceid enrolment instance id + * @return stdClass user record + */ + protected function get_enroller($instanceid) { + global $DB; + + if ($this->lasternollerinstanceid == $instanceid and $this->lasternoller) { + return $this->lasternoller; + } + + $instance = $DB->get_record('enrol', array('id'=>$instanceid, 'enrol'=>$this->get_name()), '*', MUST_EXIST); + $context = context_course::instance($instance->courseid); + + if ($users = get_enrolled_users($context, 'enrol/ilbead:manage')) { + $users = sort_by_roleassignment_authority($users, $context); + $this->lasternoller = reset($users); + unset($users); + } else { + $this->lasternoller = parent::get_enroller($instanceid); + } + + $this->lasternollerinstanceid = $instanceid; + + return $this->lasternoller; + } + + /** + * Gets an array of the user enrolment actions. + * + * @param course_enrolment_manager $manager + * @param stdClass $ue A user enrolment object + * @return array An array of user_enrolment_actions + */ + public function get_user_enrolment_actions(course_enrolment_manager $manager, $ue) { + $actions = array(); + $context = $manager->get_context(); + $instance = $ue->enrolmentinstance; + $params = $manager->get_moodlepage()->url->params(); + $params['ue'] = $ue->id; + if ($this->allow_unenrol($instance) && has_capability("enrol/ilbead:unenrol", $context)) { + $url = new moodle_url('/enrol/unenroluser.php', $params); + $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id)); + } + if ($this->allow_manage($instance) && has_capability("enrol/ilbead:manage", $context)) { + $url = new moodle_url('/enrol/editenrolment.php', $params); + $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, array('class'=>'editenrollink', 'rel'=>$ue->id)); + } + return $actions; + } + + /** + * Restore instance and map settings. + * + * @param restore_enrolments_structure_step $step + * @param stdClass $data + * @param stdClass $course + * @param int $oldid + */ + public function restore_instance(restore_enrolments_structure_step $step, stdClass $data, $course, $oldid) { + global $DB; + if ($step->get_task()->get_target() == backup::TARGET_NEW_COURSE) { + $merge = false; + } else { + $merge = array( + 'courseid' => $data->courseid, + 'enrol' => $this->get_name(), + 'roleid' => $data->roleid, + ); + } + if ($merge and $instances = $DB->get_records('enrol', $merge, 'id')) { + $instance = reset($instances); + $instanceid = $instance->id; + } else { + if (!empty($data->customint5)) { + if ($step->get_task()->is_samesite()) { + // Keep cohort restriction unchanged - we are on the same site. + } else { + // Use some id that can not exist in order to prevent self enrolment, + // because we do not know what cohort it is in this site. + $data->customint5 = -1; + } + } + $instanceid = $this->add_instance($course, (array)$data); + } + $step->set_mapping('enrol', $oldid, $instanceid); + } + + /** + * Restore user enrolment. + * + * @param restore_enrolments_structure_step $step + * @param stdClass $data + * @param stdClass $instance + * @param int $oldinstancestatus + * @param int $userid + */ + public function restore_user_enrolment(restore_enrolments_structure_step $step, $data, $instance, $userid, $oldinstancestatus) { + $this->enrol_user($instance, $userid, null, $data->timestart, $data->timeend, $data->status); + } + + /** + * Restore role assignment. + * + * @param stdClass $instance + * @param int $roleid + * @param int $userid + * @param int $contextid + */ + public function restore_role_assignment($instance, $roleid, $userid, $contextid) { + // This is necessary only because we may migrate other types to this instance, + // we do not use component in manual or self enrol. + role_assign($roleid, $userid, $contextid, '', 0); + } + + /** + * Get user ongoing EAD courses + * + * @param stdClass $instance + * @return array ongoing EAD courses + */ + + public function get_ongoing() { + global $DB; + global $USER; + return $DB->get_records_sql(" + select ue.timecreated, c.fullname + from {user_enrolments} ue + join {enrol} e on e.id = ue.enrolid + join {course} c on c.id = e.courseid + left outer join {course_completions} cc on cc.userid = ue.userid and cc.course = e.courseid + where e.enrol = 'ilbead' + and cc.timecompleted is null + and ue.timecreated > ? + and ue.userid = ?", array(time() - (60*86400), $USER->id)); + } + + /** + * Max ongoing reached + * + * @param stdClass $instance + * @return bool ongoing_reached + */ + + public function max_ongoing_reached($instance) { + if ($instance->customint7 == null or $instance->customint7 == 0) { + return false; // We have not a max ongoing, then its never reached + } + + $ongoing = $this->get_ongoing(); + + if (count($ongoing) >= $instance->customint7) { + return true; // Max ongoing reached + } + + return false; // Default max not reached + } + + /** + * Abandon courses + * Get all abandoned courses in last 'customint8' days + * + * @param stdClass $instance + * @return array of courses + */ + + public function abandon_courses($instance) { + global $DB; + global $USER; + + if ($instance->customint8 == null or $instance->customint8 == 0) { + return null; // No abandon punishment + } + + return $DB->get_records_sql(" + select ue.timecreated, c.fullname + from {user_enrolments} ue + join {enrol} e on e.id = ue.enrolid + join {course} c on c.id = e.courseid + left outer join {course_completions} cc on cc.userid = ue.userid and cc.course = e.courseid + where e.enrol = 'ilbead' + and cc.timecompleted is null + and ue.userid = ? + and ? between ue.timecreated + ? and ue.timecreated + ?", array($USER->id, time(), 60*86400, (60+$instance->customint8)*86400)); + } +} diff --git a/locallib.php b/locallib.php new file mode 100644 index 0000000..e7394c7 --- /dev/null +++ b/locallib.php @@ -0,0 +1,139 @@ +. + +/** + * Self enrol plugin implementation. + * + * @package enrol_ilbead + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once("$CFG->libdir/formslib.php"); + +class enrol_ilbead_enrol_form extends moodleform { + protected $instance; + protected $toomany = false; + + /** + * Overriding this function to get unique form id for multiple ilbead enrolments. + * + * @return string form identifier + */ + protected function get_form_identifier() { + $formid = $this->_customdata->id.'_'.get_class($this); + return $formid; + } + + public function definition() { + global $DB; + global $USER; + + $mform = $this->_form; + $instance = $this->_customdata; + $this->instance = $instance; + $plugin = enrol_get_plugin('ilbead'); + + $heading = $plugin->get_instance_name($instance); + $mform->addElement('header', 'ilbeadheader', $heading); + + if ($instance->customint3 > 0) { + // Max enrol limit specified. + $count = $DB->count_records('user_enrolments', array('enrolid'=>$instance->id)); + if ($count >= $instance->customint3) { + // Bad luck, no more ilbead enrolments here. + $this->toomany = true; + $mform->addElement('static', 'notice', '', get_string('maxenrolledreached', 'enrol_ilbead')); + return; + } + } + + if ($plugin->max_ongoing_reached($instance)) { + $ongoing = $plugin->get_ongoing($instance); + $mform->addElement('static', 'notice', '', get_string('maxongoing', 'enrol_ilbead')); + $mform->addElement('static', 'notice', '', get_string('ongoingcourses', 'enrol_ilbead')); + foreach ($ongoing as $course) { + $mform->addElement('static', 'notice', '', $course->fullname); + } + return; + } + + if ($instance->password) { + // Change the id of ilbead enrolment key input as there can be multiple ilbead enrolment methods. + $mform->addElement('passwordunmask', 'enrolpassword', get_string('password', 'enrol_ilbead'), + array('id' => 'enrolpassword_'.$instance->id)); + } else { + $mform->addElement('static', 'nokey', '', get_string('nopassword', 'enrol_ilbead')); + } + + $this->add_action_buttons(false, get_string('enrolme', 'enrol_ilbead')); + + $mform->addElement('hidden', 'id'); + $mform->setType('id', PARAM_INT); + $mform->setDefault('id', $instance->courseid); + + $mform->addElement('hidden', 'instance'); + $mform->setType('instance', PARAM_INT); + $mform->setDefault('instance', $instance->id); + } + + public function validation($data, $files) { + global $DB, $CFG; + + $errors = parent::validation($data, $files); + $instance = $this->instance; + + if ($this->toomany) { + $errors['notice'] = get_string('error'); + return $errors; + } + + if ($instance->password) { + if ($data['enrolpassword'] !== $instance->password) { + if ($instance->customint1) { + $groups = $DB->get_records('groups', array('courseid'=>$instance->courseid), 'id ASC', 'id, enrolmentkey'); + $found = false; + foreach ($groups as $group) { + if (empty($group->enrolmentkey)) { + continue; + } + if ($group->enrolmentkey === $data['enrolpassword']) { + $found = true; + break; + } + } + if (!$found) { + // We can not hint because there are probably multiple passwords. + $errors['enrolpassword'] = get_string('passwordinvalid', 'enrol_ilbead'); + } + + } else { + $plugin = enrol_get_plugin('ilbead'); + if ($plugin->get_config('showhint')) { + $hint = textlib::substr($instance->password, 0, 1); + $errors['enrolpassword'] = get_string('passwordinvalidhint', 'enrol_ilbead', $hint); + } else { + $errors['enrolpassword'] = get_string('passwordinvalid', 'enrol_ilbead'); + } + } + } + } + + return $errors; + } +} diff --git a/pix/withkey.gif b/pix/withkey.gif new file mode 100644 index 0000000..537cc1a Binary files /dev/null and b/pix/withkey.gif differ diff --git a/pix/withkey.png b/pix/withkey.png new file mode 100644 index 0000000..f2a2d16 Binary files /dev/null and b/pix/withkey.png differ diff --git a/pix/withkey.svg b/pix/withkey.svg new file mode 100644 index 0000000..6dc0520 --- /dev/null +++ b/pix/withkey.svg @@ -0,0 +1,15 @@ + + + +]> + + + + + diff --git a/pix/withoutkey.gif b/pix/withoutkey.gif new file mode 100644 index 0000000..7fb0041 Binary files /dev/null and b/pix/withoutkey.gif differ diff --git a/pix/withoutkey.png b/pix/withoutkey.png new file mode 100644 index 0000000..b00cdfd Binary files /dev/null and b/pix/withoutkey.png differ diff --git a/pix/withoutkey.svg b/pix/withoutkey.svg new file mode 100644 index 0000000..0994de6 --- /dev/null +++ b/pix/withoutkey.svg @@ -0,0 +1,15 @@ + + + +]> + + + + + diff --git a/settings.php b/settings.php new file mode 100644 index 0000000..6764511 --- /dev/null +++ b/settings.php @@ -0,0 +1,116 @@ +. + +/** + * Self enrolment plugin settings and presets. + * + * @package enrol_ilbead + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +if ($ADMIN->fulltree) { + + //--- general settings ----------------------------------------------------------------------------------- + $settings->add(new admin_setting_heading('enrol_ilbead_settings', '', get_string('pluginname_desc', 'enrol_ilbead'))); + + $settings->add(new admin_setting_configcheckbox('enrol_ilbead/requirepassword', + get_string('requirepassword', 'enrol_ilbead'), get_string('requirepassword_desc', 'enrol_ilbead'), 0)); + + $settings->add(new admin_setting_configcheckbox('enrol_ilbead/usepasswordpolicy', + get_string('usepasswordpolicy', 'enrol_ilbead'), get_string('usepasswordpolicy_desc', 'enrol_ilbead'), 0)); + + $settings->add(new admin_setting_configcheckbox('enrol_ilbead/showhint', + get_string('showhint', 'enrol_ilbead'), get_string('showhint_desc', 'enrol_ilbead'), 0)); + + // Note: let's reuse the ext sync constants and strings here, internally it is very similar, + // it describes what should happend when users are not supposed to be enerolled any more. + $options = array( + ENROL_EXT_REMOVED_KEEP => get_string('extremovedkeep', 'enrol'), + ENROL_EXT_REMOVED_SUSPENDNOROLES => get_string('extremovedsuspendnoroles', 'enrol'), + ENROL_EXT_REMOVED_UNENROL => get_string('extremovedunenrol', 'enrol'), + ); + $settings->add(new admin_setting_configselect('enrol_ilbead/expiredaction', get_string('expiredaction', 'enrol_ilbead'), get_string('expiredaction_help', 'enrol_ilbead'), ENROL_EXT_REMOVED_KEEP, $options)); + + $options = array(); + for ($i=0; $i<24; $i++) { + $options[$i] = $i; + } + $settings->add(new admin_setting_configselect('enrol_ilbead/expirynotifyhour', get_string('expirynotifyhour', 'core_enrol'), '', 6, $options)); + + //--- enrol instance defaults ---------------------------------------------------------------------------- + $settings->add(new admin_setting_heading('enrol_ilbead_defaults', + get_string('enrolinstancedefaults', 'admin'), get_string('enrolinstancedefaults_desc', 'admin'))); + + $settings->add(new admin_setting_configcheckbox('enrol_ilbead/defaultenrol', + get_string('defaultenrol', 'enrol'), get_string('defaultenrol_desc', 'enrol'), 1)); + + $options = array(ENROL_INSTANCE_ENABLED => get_string('yes'), + ENROL_INSTANCE_DISABLED => get_string('no')); + $settings->add(new admin_setting_configselect('enrol_ilbead/status', + get_string('status', 'enrol_ilbead'), get_string('status_desc', 'enrol_ilbead'), ENROL_INSTANCE_DISABLED, $options)); + + $options = array(1 => get_string('yes'), 0 => get_string('no')); + $settings->add(new admin_setting_configselect('enrol_ilbead/newenrols', + get_string('newenrols', 'enrol_ilbead'), get_string('newenrols_desc', 'enrol_ilbead'), 1, $options)); + + $options = array(1 => get_string('yes'), + 0 => get_string('no')); + $settings->add(new admin_setting_configselect('enrol_ilbead/groupkey', + get_string('groupkey', 'enrol_ilbead'), get_string('groupkey_desc', 'enrol_ilbead'), 0, $options)); + + if (!during_initial_install()) { + $options = get_default_enrol_roles(context_system::instance()); + $student = get_archetype_roles('student'); + $student = reset($student); + $settings->add(new admin_setting_configselect('enrol_ilbead/roleid', + get_string('defaultrole', 'enrol_ilbead'), get_string('defaultrole_desc', 'enrol_ilbead'), $student->id, $options)); + } + + $settings->add(new admin_setting_configduration('enrol_ilbead/enrolperiod', + get_string('enrolperiod', 'enrol_ilbead'), get_string('enrolperiod_desc', 'enrol_ilbead'), 0)); + + $options = array(0 => get_string('no'), 1 => get_string('expirynotifyenroller', 'core_enrol'), 2 => get_string('expirynotifyall', 'core_enrol')); + $settings->add(new admin_setting_configselect('enrol_ilbead/expirynotify', + get_string('expirynotify', 'core_enrol'), get_string('expirynotify_help', 'core_enrol'), 0, $options)); + + $settings->add(new admin_setting_configduration('enrol_ilbead/expirythreshold', + get_string('expirythreshold', 'core_enrol'), get_string('expirythreshold_help', 'core_enrol'), 86400, 86400)); + + $options = array(0 => get_string('never'), + 1800 * 3600 * 24 => get_string('numdays', '', 1800), + 1000 * 3600 * 24 => get_string('numdays', '', 1000), + 365 * 3600 * 24 => get_string('numdays', '', 365), + 180 * 3600 * 24 => get_string('numdays', '', 180), + 150 * 3600 * 24 => get_string('numdays', '', 150), + 120 * 3600 * 24 => get_string('numdays', '', 120), + 90 * 3600 * 24 => get_string('numdays', '', 90), + 60 * 3600 * 24 => get_string('numdays', '', 60), + 30 * 3600 * 24 => get_string('numdays', '', 30), + 21 * 3600 * 24 => get_string('numdays', '', 21), + 14 * 3600 * 24 => get_string('numdays', '', 14), + 7 * 3600 * 24 => get_string('numdays', '', 7)); + $settings->add(new admin_setting_configselect('enrol_ilbead/longtimenosee', + get_string('longtimenosee', 'enrol_ilbead'), get_string('longtimenosee_help', 'enrol_ilbead'), 0, $options)); + + $settings->add(new admin_setting_configtext('enrol_ilbead/maxenrolled', + get_string('maxenrolled', 'enrol_ilbead'), get_string('maxenrolled_help', 'enrol_ilbead'), 0, PARAM_INT)); + + $settings->add(new admin_setting_configcheckbox('enrol_ilbead/sendcoursewelcomemessage', + get_string('sendcoursewelcomemessage', 'enrol_ilbead'), get_string('sendcoursewelcomemessage_help', 'enrol_ilbead'), 1)); +} diff --git a/tests/behat/ilbead_enrolment.feature b/tests/behat/ilbead_enrolment.feature new file mode 100644 index 0000000..d801ad8 --- /dev/null +++ b/tests/behat/ilbead_enrolment.feature @@ -0,0 +1,77 @@ +@enrol @enrol_ilbead +Feature: Users can auto-enrol themself in courses where ilbead enrolment is allowed + In order to participate in courses + As a user + I need to auto enrol me in courses + + Background: + Given the following "users" exists: + | username | firstname | lastname | email | + | teacher1 | Teacher | 1 | teacher1@asd.com | + | student1 | Student | 1 | student1@asd.com | + And the following "courses" exists: + | fullname | shortname | format | + | Course 1 | C1 | topics | + And the following "course enrolments" exists: + | user | course | role | + | teacher1 | C1 | editingteacher | + + @javascript + Scenario: Self-enrolment enabled + Given I log in as "teacher1" + And I follow "Course 1" + When I add "Self enrolment" enrolment method with: + | Custom instance name | Test student enrolment | + And I log out + And I log in as "student1" + And I follow "Course 1" + And I press "Enrol me" + Then I should see "Topic 1" + And I should not see "Enrolment options" + + @javascript + Scenario: Self-enrolment enabled requiring an enrolment key + Given I log in as "teacher1" + And I follow "Course 1" + When I add "Self enrolment" enrolment method with: + | Custom instance name | Test student enrolment | + | Enrolment key | moodle_rules | + And I log out + And I log in as "student1" + And I follow "Course 1" + And I fill the moodle form with: + | Enrolment key | moodle_rules | + And I press "Enrol me" + Then I should see "Topic 1" + And I should not see "Enrolment options" + And I should not see "Enrol me in this course" + + @javascript + Scenario: Self-enrolment disabled + Given I log in as "student1" + When I follow "Course 1" + Then I should see "You can not enrol yourself in this course" + + @javascript + Scenario: Self-enrolment enabled requiring a group enrolment key + Given I log in as "teacher1" + And I follow "Course 1" + When I add "Self enrolment" enrolment method with: + | Custom instance name | Test student enrolment | + | Enrolment key | moodle_rules | + | Use group enrolment keys | Yes | + And I follow "Groups" + And I press "Create group" + And I fill the moodle form with: + | Group name | Group 1 | + | Enrolment key | testgroupenrolkey | + And I press "Save changes" + And I log out + And I log in as "student1" + And I follow "Course 1" + And I fill the moodle form with: + | Enrolment key | testgroupenrolkey | + And I press "Enrol me" + Then I should see "Topic 1" + And I should not see "Enrolment options" + And I should not see "Enrol me in this course" diff --git a/tests/ilbead_test.php b/tests/ilbead_test.php new file mode 100644 index 0000000..d713cd4 --- /dev/null +++ b/tests/ilbead_test.php @@ -0,0 +1,510 @@ +. + +/** + * Self enrolment plugin tests. + * + * @package enrol_ilbead + * @category phpunit + * @copyright 2012 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot.'/enrol/ilbead/lib.php'); +require_once($CFG->dirroot.'/enrol/ilbead/locallib.php'); + +class enrol_ilbead_testcase extends advanced_testcase { + + public function test_basics() { + $this->assertTrue(enrol_is_enabled('ilbead')); + $plugin = enrol_get_plugin('ilbead'); + $this->assertInstanceOf('enrol_ilbead_plugin', $plugin); + $this->assertEquals(1, get_config('enrol_ilbead', 'defaultenrol')); + $this->assertEquals(ENROL_EXT_REMOVED_KEEP, get_config('enrol_ilbead', 'expiredaction')); + } + + public function test_sync_nothing() { + global $SITE; + + $ilbeadplugin = enrol_get_plugin('ilbead'); + + $trace = new null_progress_trace(); + + // Just make sure the sync does not throw any errors when nothing to do. + $ilbeadplugin->sync($trace, null); + $ilbeadplugin->sync($trace, $SITE->id); + } + + public function test_longtimnosee() { + global $DB; + $this->resetAfterTest(); + + $ilbeadplugin = enrol_get_plugin('ilbead'); + $manualplugin = enrol_get_plugin('manual'); + $this->assertNotEmpty($manualplugin); + + $now = time(); + + $trace = new null_progress_trace(); + + // Prepare some data. + + $studentrole = $DB->get_record('role', array('shortname'=>'student')); + $this->assertNotEmpty($studentrole); + $teacherrole = $DB->get_record('role', array('shortname'=>'teacher')); + $this->assertNotEmpty($teacherrole); + + $record = array('firstaccess'=>$now-60*60*24*800); + $record['lastaccess'] = $now-60*60*24*100; + $user1 = $this->getDataGenerator()->create_user($record); + $record['lastaccess'] = $now-60*60*24*10; + $user2 = $this->getDataGenerator()->create_user($record); + $record['lastaccess'] = $now-60*60*24*1; + $user3 = $this->getDataGenerator()->create_user($record); + $record['lastaccess'] = $now-10; + $user4 = $this->getDataGenerator()->create_user($record); + + $course1 = $this->getDataGenerator()->create_course(); + $course2 = $this->getDataGenerator()->create_course(); + $course3 = $this->getDataGenerator()->create_course(); + $context1 = context_course::instance($course1->id); + $context2 = context_course::instance($course2->id); + $context3 = context_course::instance($course3->id); + + $this->assertEquals(3, $DB->count_records('enrol', array('enrol'=>'ilbead'))); + $instance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $id = $ilbeadplugin->add_instance($course3, array('status'=>ENROL_INSTANCE_ENABLED, 'roleid'=>$teacherrole->id)); + $instance3b = $DB->get_record('enrol', array('id'=>$id), '*', MUST_EXIST); + unset($id); + + $this->assertEquals($studentrole->id, $instance1->roleid); + $instance1->customint2 = 60*60*24*14; + $DB->update_record('enrol', $instance1); + $ilbeadplugin->enrol_user($instance1, $user1->id, $studentrole->id); + $ilbeadplugin->enrol_user($instance1, $user2->id, $studentrole->id); + $ilbeadplugin->enrol_user($instance1, $user3->id, $studentrole->id); + $this->assertEquals(3, $DB->count_records('user_enrolments')); + $DB->insert_record('user_lastaccess', array('userid'=>$user2->id, 'courseid'=>$course1->id, 'timeaccess'=>$now-60*60*24*20)); + $DB->insert_record('user_lastaccess', array('userid'=>$user3->id, 'courseid'=>$course1->id, 'timeaccess'=>$now-60*60*24*2)); + $DB->insert_record('user_lastaccess', array('userid'=>$user4->id, 'courseid'=>$course1->id, 'timeaccess'=>$now-60)); + + $this->assertEquals($studentrole->id, $instance3->roleid); + $instance3->customint2 = 60*60*24*50; + $DB->update_record('enrol', $instance3); + $ilbeadplugin->enrol_user($instance3, $user1->id, $studentrole->id); + $ilbeadplugin->enrol_user($instance3, $user2->id, $studentrole->id); + $ilbeadplugin->enrol_user($instance3, $user3->id, $studentrole->id); + $ilbeadplugin->enrol_user($instance3b, $user1->id, $teacherrole->id); + $ilbeadplugin->enrol_user($instance3b, $user4->id, $teacherrole->id); + $this->assertEquals(8, $DB->count_records('user_enrolments')); + $DB->insert_record('user_lastaccess', array('userid'=>$user2->id, 'courseid'=>$course3->id, 'timeaccess'=>$now-60*60*24*11)); + $DB->insert_record('user_lastaccess', array('userid'=>$user3->id, 'courseid'=>$course3->id, 'timeaccess'=>$now-60*60*24*200)); + $DB->insert_record('user_lastaccess', array('userid'=>$user4->id, 'courseid'=>$course3->id, 'timeaccess'=>$now-60*60*24*200)); + + $maninstance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual'), '*', MUST_EXIST); + $maninstance3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual'), '*', MUST_EXIST); + + $manualplugin->enrol_user($maninstance2, $user1->id, $studentrole->id); + $manualplugin->enrol_user($maninstance3, $user1->id, $teacherrole->id); + + $this->assertEquals(10, $DB->count_records('user_enrolments')); + $this->assertEquals(9, $DB->count_records('role_assignments')); + $this->assertEquals(7, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id))); + $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id))); + + // Execute sync - this is the same thing used from cron. + + $ilbeadplugin->sync($trace, $course2->id); + $this->assertEquals(10, $DB->count_records('user_enrolments')); + + $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user1->id))); + $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user2->id))); + $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user1->id))); + $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user3->id))); + $ilbeadplugin->sync($trace, null); + $this->assertEquals(6, $DB->count_records('user_enrolments')); + $this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user1->id))); + $this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user2->id))); + $this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user1->id))); + $this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user3->id))); + + $this->assertEquals(6, $DB->count_records('role_assignments')); + $this->assertEquals(4, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id))); + $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id))); + } + + public function test_expired() { + global $DB; + $this->resetAfterTest(); + + $ilbeadplugin = enrol_get_plugin('ilbead'); + $manualplugin = enrol_get_plugin('manual'); + $this->assertNotEmpty($manualplugin); + + $now = time(); + + $trace = new null_progress_trace(); + + // Prepare some data. + + $studentrole = $DB->get_record('role', array('shortname'=>'student')); + $this->assertNotEmpty($studentrole); + $teacherrole = $DB->get_record('role', array('shortname'=>'teacher')); + $this->assertNotEmpty($teacherrole); + $managerrole = $DB->get_record('role', array('shortname'=>'manager')); + $this->assertNotEmpty($managerrole); + + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + $user3 = $this->getDataGenerator()->create_user(); + $user4 = $this->getDataGenerator()->create_user(); + + $course1 = $this->getDataGenerator()->create_course(); + $course2 = $this->getDataGenerator()->create_course(); + $course3 = $this->getDataGenerator()->create_course(); + $context1 = context_course::instance($course1->id); + $context2 = context_course::instance($course2->id); + $context3 = context_course::instance($course3->id); + + $this->assertEquals(3, $DB->count_records('enrol', array('enrol'=>'ilbead'))); + $instance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $this->assertEquals($studentrole->id, $instance1->roleid); + $instance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $this->assertEquals($studentrole->id, $instance2->roleid); + $instance3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $this->assertEquals($studentrole->id, $instance3->roleid); + $id = $ilbeadplugin->add_instance($course3, array('status'=>ENROL_INSTANCE_ENABLED, 'roleid'=>$teacherrole->id)); + $instance3b = $DB->get_record('enrol', array('id'=>$id), '*', MUST_EXIST); + $this->assertEquals($teacherrole->id, $instance3b->roleid); + unset($id); + + $maninstance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual'), '*', MUST_EXIST); + $maninstance3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual'), '*', MUST_EXIST); + + $manualplugin->enrol_user($maninstance2, $user1->id, $studentrole->id); + $manualplugin->enrol_user($maninstance3, $user1->id, $teacherrole->id); + + $this->assertEquals(2, $DB->count_records('user_enrolments')); + $this->assertEquals(2, $DB->count_records('role_assignments')); + $this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id))); + $this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id))); + + $ilbeadplugin->enrol_user($instance1, $user1->id, $studentrole->id); + $ilbeadplugin->enrol_user($instance1, $user2->id, $studentrole->id); + $ilbeadplugin->enrol_user($instance1, $user3->id, $studentrole->id, 0, $now-60); + + $ilbeadplugin->enrol_user($instance3, $user1->id, $studentrole->id, 0, 0); + $ilbeadplugin->enrol_user($instance3, $user2->id, $studentrole->id, 0, $now-60*60); + $ilbeadplugin->enrol_user($instance3, $user3->id, $studentrole->id, 0, $now+60*60); + $ilbeadplugin->enrol_user($instance3b, $user1->id, $teacherrole->id, $now-60*60*24*7, $now-60); + $ilbeadplugin->enrol_user($instance3b, $user4->id, $teacherrole->id); + + role_assign($managerrole->id, $user3->id, $context1->id); + + $this->assertEquals(10, $DB->count_records('user_enrolments')); + $this->assertEquals(10, $DB->count_records('role_assignments')); + $this->assertEquals(7, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id))); + $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id))); + + // Execute tests. + + $this->assertEquals(ENROL_EXT_REMOVED_KEEP, $ilbeadplugin->get_config('expiredaction')); + $ilbeadplugin->sync($trace, null); + $this->assertEquals(10, $DB->count_records('user_enrolments')); + $this->assertEquals(10, $DB->count_records('role_assignments')); + + + $ilbeadplugin->set_config('expiredaction', ENROL_EXT_REMOVED_SUSPENDNOROLES); + $ilbeadplugin->sync($trace, $course2->id); + $this->assertEquals(10, $DB->count_records('user_enrolments')); + $this->assertEquals(10, $DB->count_records('role_assignments')); + + $ilbeadplugin->sync($trace, null); + $this->assertEquals(10, $DB->count_records('user_enrolments')); + $this->assertEquals(7, $DB->count_records('role_assignments')); + $this->assertEquals(5, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id))); + $this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id))); + $this->assertFalse($DB->record_exists('role_assignments', array('contextid'=>$context1->id, 'userid'=>$user3->id, 'roleid'=>$studentrole->id))); + $this->assertFalse($DB->record_exists('role_assignments', array('contextid'=>$context3->id, 'userid'=>$user2->id, 'roleid'=>$studentrole->id))); + $this->assertFalse($DB->record_exists('role_assignments', array('contextid'=>$context3->id, 'userid'=>$user1->id, 'roleid'=>$teacherrole->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('contextid'=>$context3->id, 'userid'=>$user1->id, 'roleid'=>$studentrole->id))); + + + $ilbeadplugin->set_config('expiredaction', ENROL_EXT_REMOVED_UNENROL); + + role_assign($studentrole->id, $user3->id, $context1->id); + role_assign($studentrole->id, $user2->id, $context3->id); + role_assign($teacherrole->id, $user1->id, $context3->id); + $this->assertEquals(10, $DB->count_records('user_enrolments')); + $this->assertEquals(10, $DB->count_records('role_assignments')); + $this->assertEquals(7, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id))); + $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id))); + + $ilbeadplugin->sync($trace, null); + $this->assertEquals(7, $DB->count_records('user_enrolments')); + $this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user3->id))); + $this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user2->id))); + $this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3b->id, 'userid'=>$user1->id))); + $this->assertEquals(6, $DB->count_records('role_assignments')); + $this->assertEquals(5, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id))); + $this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id))); + } + + public function test_send_expiry_notifications() { + global $DB, $CFG; + $this->resetAfterTest(); + $this->preventResetByRollback(); // Messaging does not like transactions... + + /** @var $ilbeadplugin enrol_ilbead_plugin */ + $ilbeadplugin = enrol_get_plugin('ilbead'); + /** @var $manualplugin enrol_manual_plugin */ + $manualplugin = enrol_get_plugin('manual'); + $now = time(); + $admin = get_admin(); + + $trace = new null_progress_trace(); + + // Note: hopefully nobody executes the unit tests the last second before midnight... + + $ilbeadplugin->set_config('expirynotifylast', $now - 60*60*24); + $ilbeadplugin->set_config('expirynotifyhour', 0); + + $studentrole = $DB->get_record('role', array('shortname'=>'student')); + $this->assertNotEmpty($studentrole); + $editingteacherrole = $DB->get_record('role', array('shortname'=>'editingteacher')); + $this->assertNotEmpty($editingteacherrole); + $managerrole = $DB->get_record('role', array('shortname'=>'manager')); + $this->assertNotEmpty($managerrole); + + $user1 = $this->getDataGenerator()->create_user(array('lastname'=>'xuser1')); + $user2 = $this->getDataGenerator()->create_user(array('lastname'=>'xuser2')); + $user3 = $this->getDataGenerator()->create_user(array('lastname'=>'xuser3')); + $user4 = $this->getDataGenerator()->create_user(array('lastname'=>'xuser4')); + $user5 = $this->getDataGenerator()->create_user(array('lastname'=>'xuser5')); + $user6 = $this->getDataGenerator()->create_user(array('lastname'=>'xuser6')); + $user7 = $this->getDataGenerator()->create_user(array('lastname'=>'xuser6')); + $user8 = $this->getDataGenerator()->create_user(array('lastname'=>'xuser6')); + + $course1 = $this->getDataGenerator()->create_course(array('fullname'=>'xcourse1')); + $course2 = $this->getDataGenerator()->create_course(array('fullname'=>'xcourse2')); + $course3 = $this->getDataGenerator()->create_course(array('fullname'=>'xcourse3')); + $course4 = $this->getDataGenerator()->create_course(array('fullname'=>'xcourse4')); + + $this->assertEquals(4, $DB->count_records('enrol', array('enrol'=>'manual'))); + $this->assertEquals(4, $DB->count_records('enrol', array('enrol'=>'ilbead'))); + + $maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST); + $instance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance1->expirythreshold = 60*60*24*4; + $instance1->expirynotify = 1; + $instance1->notifyall = 1; + $instance1->status = ENROL_INSTANCE_ENABLED; + $DB->update_record('enrol', $instance1); + + $maninstance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual'), '*', MUST_EXIST); + $instance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance2->expirythreshold = 60*60*24*1; + $instance2->expirynotify = 1; + $instance2->notifyall = 1; + $instance2->status = ENROL_INSTANCE_ENABLED; + $DB->update_record('enrol', $instance2); + + $maninstance3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual'), '*', MUST_EXIST); + $instance3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance3->expirythreshold = 60*60*24*1; + $instance3->expirynotify = 1; + $instance3->notifyall = 0; + $instance3->status = ENROL_INSTANCE_ENABLED; + $DB->update_record('enrol', $instance3); + + $maninstance4 = $DB->get_record('enrol', array('courseid'=>$course4->id, 'enrol'=>'manual'), '*', MUST_EXIST); + $instance4 = $DB->get_record('enrol', array('courseid'=>$course4->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance4->expirythreshold = 60*60*24*1; + $instance4->expirynotify = 0; + $instance4->notifyall = 0; + $instance4->status = ENROL_INSTANCE_ENABLED; + $DB->update_record('enrol', $instance4); + + $ilbeadplugin->enrol_user($instance1, $user1->id, $studentrole->id, 0, $now + 60*60*24*1, ENROL_USER_SUSPENDED); // Suspended users are not notified. + $ilbeadplugin->enrol_user($instance1, $user2->id, $studentrole->id, 0, $now + 60*60*24*5); // Above threshold are not notified. + $ilbeadplugin->enrol_user($instance1, $user3->id, $studentrole->id, 0, $now + 60*60*24*3 + 60*60); // Less than one day after threshold - should be notified. + $ilbeadplugin->enrol_user($instance1, $user4->id, $studentrole->id, 0, $now + 60*60*24*4 - 60*3); // Less than one day after threshold - should be notified. + $ilbeadplugin->enrol_user($instance1, $user5->id, $studentrole->id, 0, $now + 60*60); // Should have been already notified. + $ilbeadplugin->enrol_user($instance1, $user6->id, $studentrole->id, 0, $now - 60); // Already expired. + $manualplugin->enrol_user($maninstance1, $user7->id, $editingteacherrole->id); + $manualplugin->enrol_user($maninstance1, $user8->id, $managerrole->id); // Highest role --> enroller. + + $ilbeadplugin->enrol_user($instance2, $user1->id, $studentrole->id); + $ilbeadplugin->enrol_user($instance2, $user2->id, $studentrole->id, 0, $now + 60*60*24*1 + 60*3); // Above threshold are not notified. + $ilbeadplugin->enrol_user($instance2, $user3->id, $studentrole->id, 0, $now + 60*60*24*1 - 60*60); // Less than one day after threshold - should be notified. + + $manualplugin->enrol_user($maninstance3, $user1->id, $editingteacherrole->id); + $ilbeadplugin->enrol_user($instance3, $user2->id, $studentrole->id, 0, $now + 60*60*24*1 + 60); // Above threshold are not notified. + $ilbeadplugin->enrol_user($instance3, $user3->id, $studentrole->id, 0, $now + 60*60*24*1 - 60*60); // Less than one day after threshold - should be notified. + + $manualplugin->enrol_user($maninstance4, $user4->id, $editingteacherrole->id); + $ilbeadplugin->enrol_user($instance4, $user5->id, $studentrole->id, 0, $now + 60*60*24*1 + 60); + $ilbeadplugin->enrol_user($instance4, $user6->id, $studentrole->id, 0, $now + 60*60*24*1 - 60*60); + + // The notification is sent out in fixed order first individual users, + // then summary per course by enrolid, user lastname, etc. + $this->assertGreaterThan($instance1->id, $instance2->id); + $this->assertGreaterThan($instance2->id, $instance3->id); + + $sink = $this->redirectMessages(); + + $ilbeadplugin->send_expiry_notifications($trace); + + $messages = $sink->get_messages(); + + $this->assertEquals(2+1 + 1+1 + 1 + 0, count($messages)); + + // First individual notifications from course1. + $this->assertEquals($user3->id, $messages[0]->useridto); + $this->assertEquals($user8->id, $messages[0]->useridfrom); + $this->assertContains('xcourse1', $messages[0]->fullmessagehtml); + + $this->assertEquals($user4->id, $messages[1]->useridto); + $this->assertEquals($user8->id, $messages[1]->useridfrom); + $this->assertContains('xcourse1', $messages[1]->fullmessagehtml); + + // Then summary for course1. + $this->assertEquals($user8->id, $messages[2]->useridto); + $this->assertEquals($admin->id, $messages[2]->useridfrom); + $this->assertContains('xcourse1', $messages[2]->fullmessagehtml); + $this->assertNotContains('xuser1', $messages[2]->fullmessagehtml); + $this->assertNotContains('xuser2', $messages[2]->fullmessagehtml); + $this->assertContains('xuser3', $messages[2]->fullmessagehtml); + $this->assertContains('xuser4', $messages[2]->fullmessagehtml); + $this->assertContains('xuser5', $messages[2]->fullmessagehtml); + $this->assertNotContains('xuser6', $messages[2]->fullmessagehtml); + + // First individual notifications from course2. + $this->assertEquals($user3->id, $messages[3]->useridto); + $this->assertEquals($admin->id, $messages[3]->useridfrom); + $this->assertContains('xcourse2', $messages[3]->fullmessagehtml); + + // Then summary for course2. + $this->assertEquals($admin->id, $messages[4]->useridto); + $this->assertEquals($admin->id, $messages[4]->useridfrom); + $this->assertContains('xcourse2', $messages[4]->fullmessagehtml); + $this->assertNotContains('xuser1', $messages[4]->fullmessagehtml); + $this->assertNotContains('xuser2', $messages[4]->fullmessagehtml); + $this->assertContains('xuser3', $messages[4]->fullmessagehtml); + $this->assertNotContains('xuser4', $messages[4]->fullmessagehtml); + $this->assertNotContains('xuser5', $messages[4]->fullmessagehtml); + $this->assertNotContains('xuser6', $messages[4]->fullmessagehtml); + + // Only summary in course3. + $this->assertEquals($user1->id, $messages[5]->useridto); + $this->assertEquals($admin->id, $messages[5]->useridfrom); + $this->assertContains('xcourse3', $messages[5]->fullmessagehtml); + $this->assertNotContains('xuser1', $messages[5]->fullmessagehtml); + $this->assertNotContains('xuser2', $messages[5]->fullmessagehtml); + $this->assertContains('xuser3', $messages[5]->fullmessagehtml); + $this->assertNotContains('xuser4', $messages[5]->fullmessagehtml); + $this->assertNotContains('xuser5', $messages[5]->fullmessagehtml); + $this->assertNotContains('xuser6', $messages[5]->fullmessagehtml); + + + // Make sure that notifications are not repeated. + $sink->clear(); + + $ilbeadplugin->send_expiry_notifications($trace); + $this->assertEquals(0, $sink->count()); + + // use invalid notification hour to verify that before the hour the notifications are not sent. + $ilbeadplugin->set_config('expirynotifylast', time() - 60*60*24); + $ilbeadplugin->set_config('expirynotifyhour', '24'); + + $ilbeadplugin->send_expiry_notifications($trace); + $this->assertEquals(0, $sink->count()); + + $ilbeadplugin->set_config('expirynotifyhour', '0'); + $ilbeadplugin->send_expiry_notifications($trace); + $this->assertEquals(6, $sink->count()); + } + + public function test_show_enrolme_link() { + global $DB, $CFG; + $this->resetAfterTest(); + $this->preventResetByRollback(); // Messaging does not like transactions... + + /** @var $ilbeadplugin enrol_ilbead_plugin */ + $ilbeadplugin = enrol_get_plugin('ilbead'); + + $user1 = $this->getDataGenerator()->create_user(); + + $course1 = $this->getDataGenerator()->create_course(); + $course2 = $this->getDataGenerator()->create_course(); + $course3 = $this->getDataGenerator()->create_course(); + $course4 = $this->getDataGenerator()->create_course(); + $course5 = $this->getDataGenerator()->create_course(); + + $cohort1 = $this->getDataGenerator()->create_cohort(); + $cohort2 = $this->getDataGenerator()->create_cohort(); + + $instance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance1->customint6 = 1; + $DB->update_record('enrol', $instance1); + $ilbeadplugin->update_status($instance1, ENROL_INSTANCE_ENABLED); + + $instance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance2->customint6 = 0; + $DB->update_record('enrol', $instance2); + $ilbeadplugin->update_status($instance2, ENROL_INSTANCE_ENABLED); + + $instance3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance3->customint6 = 1; + $DB->update_record('enrol', $instance3); + $ilbeadplugin->update_status($instance3, ENROL_INSTANCE_DISABLED); + + $instance4 = $DB->get_record('enrol', array('courseid'=>$course4->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance4->customint6 = 0; + $DB->update_record('enrol', $instance4); + $ilbeadplugin->update_status($instance4, ENROL_INSTANCE_DISABLED); + + $instance5 = $DB->get_record('enrol', array('courseid'=>$course5->id, 'enrol'=>'ilbead'), '*', MUST_EXIST); + $instance5->customint6 = 1; + $instance5->customint5 = $cohort1->id; + $DB->update_record('enrol', $instance1); + $ilbeadplugin->update_status($instance5, ENROL_INSTANCE_ENABLED); + + $id = $ilbeadplugin->add_instance($course5, $ilbeadplugin->get_instance_defaults()); + $instance6 = $DB->get_record('enrol', array('id'=>$id), '*', MUST_EXIST); + $instance6->customint6 = 1; + $instance6->customint5 = $cohort2->id; + $DB->update_record('enrol', $instance1); + $ilbeadplugin->update_status($instance6, ENROL_INSTANCE_ENABLED); + + $this->setUser($user1); + $this->assertTrue($ilbeadplugin->show_enrolme_link($instance1)); + $this->assertFalse($ilbeadplugin->show_enrolme_link($instance2)); + $this->assertFalse($ilbeadplugin->show_enrolme_link($instance3)); + $this->assertFalse($ilbeadplugin->show_enrolme_link($instance4)); + + require_once("$CFG->dirroot/cohort/lib.php"); + cohort_add_member($cohort1->id, $user1->id); + + $this->assertTrue($ilbeadplugin->show_enrolme_link($instance5)); + $this->assertFalse($ilbeadplugin->show_enrolme_link($instance6)); + } +} diff --git a/unenrolilbead.php b/unenrolilbead.php new file mode 100644 index 0000000..545a89b --- /dev/null +++ b/unenrolilbead.php @@ -0,0 +1,61 @@ +. + +/** + * Self enrolment plugin - support for user ilbead unenrolment. + * + * @package enrol_ilbead + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../config.php'); + +$enrolid = required_param('enrolid', PARAM_INT); +$confirm = optional_param('confirm', 0, PARAM_BOOL); + +$instance = $DB->get_record('enrol', array('id'=>$enrolid, 'enrol'=>'ilbead'), '*', MUST_EXIST); +$course = $DB->get_record('course', array('id'=>$instance->courseid), '*', MUST_EXIST); +$context = context_course::instance($course->id, MUST_EXIST); + +require_login(); +if (!is_enrolled($context)) { + redirect(new moodle_url('/')); +} +require_login($course); + +$plugin = enrol_get_plugin('ilbead'); + +// Security defined inside following function. +if (!$plugin->get_unenrolilbead_link($instance)) { + redirect(new moodle_url('/course/view.php', array('id'=>$course->id))); +} + +$PAGE->set_url('/enrol/ilbead/unenrolilbead.php', array('enrolid'=>$instance->id)); +$PAGE->set_title($plugin->get_instance_name($instance)); + +if ($confirm and confirm_sesskey()) { + $plugin->unenrol_user($instance, $USER->id); + add_to_log($course->id, 'course', 'unenrol', '../enrol/users.php?id='.$course->id, $course->id); //TODO: there should be userid somewhere! + redirect(new moodle_url('/index.php')); +} + +echo $OUTPUT->header(); +$yesurl = new moodle_url($PAGE->url, array('confirm'=>1, 'sesskey'=>sesskey())); +$nourl = new moodle_url('/course/view.php', array('id'=>$course->id)); +$message = get_string('unenrolilbeadconfirm', 'enrol_ilbead', format_string($course->fullname)); +echo $OUTPUT->confirm($message, $yesurl, $nourl); +echo $OUTPUT->footer(); diff --git a/version.php b/version.php new file mode 100644 index 0000000..0f9f53c --- /dev/null +++ b/version.php @@ -0,0 +1,30 @@ +. + +/** + * Self enrolment plugin version specification. + * + * @package enrol_ilbead + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->version = 2013050101; // The current plugin version (Date: YYYYMMDDXX) +$plugin->requires = 2013050100; // Requires this Moodle version +$plugin->component = 'enrol_ilbead'; // Full name of the plugin (used for diagnostics) +$plugin->cron = 600;