From df997f841f93d676d782a46cfb8547ebc7319102 Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Mon, 21 Jun 2010 15:30:49 +0000 Subject: [PATCH] MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week AMOS START MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self] MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self] MOV [enrolstartdate,core],[enrolstartdate,enrol_self] MOV [enrolenddate,core],[enrolenddate,enrol_self] CPY [welcometocourse,core],[welcometocourse,enrol_self] CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self] MOV [notenrollable,core],[notenrollable,core_enrol] MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self] MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self] MOV [coursemanager,core_admin],[coursecontact,core_admin] MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin] MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual] MOV [enrolme,core],[enrolme,core_enrol] MOV [unenrol,core],[unenrol,core_enrol] MOV [unenrolme,core],[unenrolme,core_enrol] MOV [enrolmentnew,core],[enrolmentnew,core_enrol] MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol] MOV [enrolments,core],[enrolments,core_enrol] MOV [enrolperiod,core],[enrolperiod,core_enrol] MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol] AMOS END --- admin/bloglevelupgrade.php | 2 +- admin/cron.php | 88 +- admin/enrol.php | 215 ++- admin/enrol_config.php | 70 - admin/generator.php | 21 +- admin/mnet/enr_course_enrol.php | 9 +- admin/mnet/enr_courses.php | 7 +- admin/mnet/enr_hosts.php | 6 +- .../security/lang/en/report_security.php | 18 - admin/report/security/lib.php | 191 +-- admin/roles/assign.php | 111 +- admin/roles/check.php | 8 +- admin/roles/lib.php | 56 +- admin/roles/manage.php | 1 - admin/roles/override.php | 9 +- admin/roles/permissions.php | 11 - admin/roles/tabs.php | 116 -- admin/roles/usersroles.php | 2 +- admin/settings/appearance.php | 6 +- admin/settings/courses.php | 48 - admin/settings/frontpage.php | 1 - admin/settings/plugins.php | 82 +- admin/settings/security.php | 1 + admin/settings/users.php | 60 +- admin/uploaduser.php | 218 ++- admin/uploaduser_form.php | 44 +- admin/user/user_bulk_enrol.php | 16 +- admin/webservice/testclient_forms.php | 131 +- auth/cas/auth.php | 10 +- auth/fc/auth.php | 4 +- auth/ldap/auth.php | 10 +- auth/mnet/auth.php | 28 +- auth/shibboleth/index.php | 2 +- backup/backuplib.php | 5 +- backup/moodle2/backup_course_task.class.php | 4 +- backup/moodle2/backup_final_task.class.php | 2 + backup/moodle2/backup_stepslib.php | 22 +- backup/restore_check.html | 13 +- backup/restore_form.html | 31 +- backup/restorelib.php | 12 +- blocks/course_list/block_course_list.php | 5 +- .../course_overview/block_course_overview.php | 2 +- .../course_summary/block_course_summary.php | 2 +- blocks/course_summary/db/upgrade.php | 2 +- calendar/export_execute.php | 2 +- calendar/lib.php | 7 +- calendar/view.php | 2 +- cohort/edit.php | 1 + cohort/lib.php | 59 +- course/category.php | 19 +- course/edit.php | 272 ++-- course/edit_form.php | 305 +--- course/enrol.php | 111 +- course/external.php | 749 ---------- course/externallib.php | 6 +- course/importstudents.html | 80 - course/importstudents.php | 170 --- course/index.php | 23 +- course/info.php | 18 +- course/lib.php | 433 +++--- course/pending.php | 7 +- course/renderer.php | 18 +- course/report/completion/lib.php | 2 + course/report/log/lib.php | 9 +- course/request_form.php | 5 - course/reset_form.php | 8 +- course/unenrol.php | 123 -- course/user.php | 3 +- enrol/authorize/db/upgrade.php | 2 +- enrol/authorize/enrol.php | 6 +- enrol/authorize/locallib.php | 6 +- enrol/authorize/uploadcsv.php | 3 +- enrol/category/cli/sync.php | 38 + enrol/category/db/access.php | 38 + enrol/category/db/events.php | 40 + enrol/category/db/install.php | 69 + enrol/category/lang/en/enrol_category.php | 28 + enrol/category/lib.php | 97 ++ enrol/category/locallib.php | 323 +++++ enrol/category/settings.php | 37 + enrol/category/version.php | 27 + enrol/cohort/addinstance.php | 60 + enrol/cohort/addinstance_form.php | 72 + enrol/cohort/db/access.php | 37 + enrol/cohort/db/events.php | 45 + enrol/cohort/lang/en/enrol_cohort.php | 28 + enrol/cohort/lib.php | 118 ++ enrol/cohort/locallib.php | 189 +++ enrol/cohort/settings.php | 44 + enrol/cohort/version.php | 27 + enrol/database/cli/sync.php | 40 + enrol/database/config.html | 251 ---- enrol/database/db/access.php | 45 + enrol/database/db/install.php | 107 ++ enrol/database/enrol.php | 681 --------- enrol/database/enrol_database_sync.php | 41 - enrol/database/lang/en/enrol_database.php | 93 +- enrol/database/lib.php | 487 +++++++ enrol/database/settings.php | 115 ++ enrol/database/version.php | 27 + enrol/enrol.class.php | 22 - enrol/externallib.php | 165 ++- enrol/flatfile/enrol.php | 5 +- enrol/guest/addinstance.php | 43 + enrol/guest/db/access.php | 39 + enrol/guest/lang/en/enrol_guest.php | 40 + enrol/guest/lib.php | 291 ++++ enrol/guest/locallib.php | 76 + enrol/guest/settings.php | 56 + enrol/guest/version.php | 26 + enrol/imsenterprise/enrol.php | 12 +- enrol/index.html | 1 - enrol/index.php | 99 ++ enrol/instances.php | 237 +++ enrol/ldap/enrol.php | 16 +- enrol/ldap/enrol_ldap_sync.php | 5 - enrol/manual/addinstance.php | 43 + enrol/manual/config.html | 63 - enrol/manual/db/access.php | 64 + enrol/manual/db/install.php | 32 + enrol/manual/enrol.html | 47 - enrol/manual/enrol.php | 455 ------ enrol/manual/lang/en/enrol_manual.php | 29 +- enrol/manual/lib.php | 222 +++ enrol/manual/locallib.php | 154 ++ enrol/manual/manage.php | 188 +++ enrol/manual/settings.php | 60 + enrol/manual/unenrolself.php | 58 + enrol/manual/version.php | 26 + enrol/meta/addinstance.php | 60 + enrol/meta/addinstance_form.php | 96 ++ enrol/meta/db/access.php | 45 + enrol/meta/db/events.php | 57 + enrol/meta/db/install.php | 42 + enrol/meta/lang/en/enrol_meta.php | 32 + enrol/meta/lib.php | 107 ++ enrol/meta/locallib.php | 317 ++++ enrol/meta/settings.php | 41 + enrol/meta/version.php | 27 + enrol/mnet/enrol.php | 4 +- enrol/otherusers.php | 91 ++ enrol/paypal/enrol.php | 3 - enrol/paypal/ipn.php | 2 +- enrol/paypal/return.php | 2 +- enrol/self/addinstance.php | 43 + enrol/self/db/access.php | 52 + enrol/self/db/install.php | 10 + enrol/self/lang/en/enrol_self.php | 63 + enrol/self/lib.php | 433 ++++++ enrol/self/locallib.php | 84 ++ enrol/self/settings.php | 79 + enrol/self/unenrolself.php | 58 + enrol/self/version.php | 26 + enrol/users.php | 518 +++++++ enrol/users_forms.php | 203 +++ grade/querylib.php | 2 +- grade/report/overview/lib.php | 4 +- group/assign.php | 6 +- group/autogroup_form.php | 10 +- group/group_form.php | 4 +- group/index.php | 6 +- group/lib.php | 24 +- index.php | 2 +- lang/en/admin.php | 21 +- lang/en/enrol.php | 63 + lang/en/error.php | 7 +- lang/en/group.php | 3 + lang/en/moodle.php | 85 +- lang/en/role.php | 11 +- lib/accesslib.php | 1119 +++++--------- lib/adminlib.php | 267 +++- .../completion_criteria_duration.php | 2 + lib/completion/cron.php | 2 + lib/datalib.php | 445 +----- lib/db/access.php | 66 +- lib/db/events.php | 32 +- lib/db/install.php | 7 +- lib/db/install.xml | 165 ++- lib/db/services.php | 17 +- lib/db/upgrade.php | 842 +++++++++-- lib/ddl/mysql_sql_generator.php | 3 +- lib/deprecatedlib.php | 33 + lib/enrollib.php | 1284 +++++++++++++++++ lib/eventslib.php | 6 + lib/externallib.php | 22 +- lib/file/file_browser.php | 4 +- lib/file/file_info_course.php | 2 +- lib/gradelib.php | 28 + lib/moodlelib.php | 685 ++++----- lib/navigationlib.php | 134 +- lib/outputrequirementslib.php | 6 +- lib/sessionlib.php | 14 +- lib/setup.php | 1 + lib/setuplib.php | 13 +- lib/simpletest/broken_testfilelib.php | 2 +- lib/simpletest/testaccesslib.php | 35 +- lib/upgradelib.php | 6 +- message/lib.php | 2 +- mod/assignment/db/events.php | 36 + mod/choice/view.php | 2 +- mod/feedback/show_entries.php | 30 +- mod/feedback/show_nonrespondents.php | 32 +- mod/forum/db/events.php | 39 + mod/forum/db/upgrade.php | 28 - mod/forum/lib.php | 45 +- mod/forum/post.php | 4 +- notes/index.php | 2 +- pluginfile.php | 25 +- question/type/randomsamatch/questiontype.php | 2 +- repository/lib.php | 2 +- rss/file.php | 24 +- search/documents/label_document.php | 2 +- search/documents/resource_document.php | 2 +- search/querylib.php | 2 +- tag/coursetagslib.php | 3 +- tag/locallib.php | 2 +- user/action_redir.php | 2 - user/extendenrol.php | 188 --- user/groupextendenrol.php | 185 --- user/index.php | 99 +- user/lib.php | 5 +- user/profile.php | 9 +- user/selector/lib.php | 11 +- user/view.php | 9 +- version.php | 2 +- 225 files changed, 11062 insertions(+), 7646 deletions(-) delete mode 100644 admin/enrol_config.php delete mode 100755 admin/roles/tabs.php delete mode 100644 course/external.php delete mode 100644 course/importstudents.html delete mode 100644 course/importstudents.php delete mode 100644 course/unenrol.php create mode 100644 enrol/category/cli/sync.php create mode 100644 enrol/category/db/access.php create mode 100644 enrol/category/db/events.php create mode 100644 enrol/category/db/install.php create mode 100644 enrol/category/lang/en/enrol_category.php create mode 100644 enrol/category/lib.php create mode 100644 enrol/category/locallib.php create mode 100644 enrol/category/settings.php create mode 100644 enrol/category/version.php create mode 100644 enrol/cohort/addinstance.php create mode 100644 enrol/cohort/addinstance_form.php create mode 100644 enrol/cohort/db/access.php create mode 100644 enrol/cohort/db/events.php create mode 100644 enrol/cohort/lang/en/enrol_cohort.php create mode 100644 enrol/cohort/lib.php create mode 100644 enrol/cohort/locallib.php create mode 100644 enrol/cohort/settings.php create mode 100644 enrol/cohort/version.php create mode 100644 enrol/database/cli/sync.php delete mode 100644 enrol/database/config.html create mode 100644 enrol/database/db/access.php create mode 100644 enrol/database/db/install.php delete mode 100644 enrol/database/enrol.php delete mode 100644 enrol/database/enrol_database_sync.php create mode 100644 enrol/database/lib.php create mode 100644 enrol/database/settings.php create mode 100644 enrol/database/version.php delete mode 100644 enrol/enrol.class.php create mode 100644 enrol/guest/addinstance.php create mode 100644 enrol/guest/db/access.php create mode 100644 enrol/guest/lang/en/enrol_guest.php create mode 100644 enrol/guest/lib.php create mode 100644 enrol/guest/locallib.php create mode 100644 enrol/guest/settings.php create mode 100644 enrol/guest/version.php delete mode 100644 enrol/index.html create mode 100644 enrol/index.php create mode 100644 enrol/instances.php create mode 100644 enrol/manual/addinstance.php delete mode 100644 enrol/manual/config.html create mode 100644 enrol/manual/db/access.php create mode 100644 enrol/manual/db/install.php delete mode 100644 enrol/manual/enrol.html delete mode 100644 enrol/manual/enrol.php create mode 100644 enrol/manual/lib.php create mode 100644 enrol/manual/locallib.php create mode 100644 enrol/manual/manage.php create mode 100644 enrol/manual/settings.php create mode 100644 enrol/manual/unenrolself.php create mode 100644 enrol/manual/version.php create mode 100644 enrol/meta/addinstance.php create mode 100644 enrol/meta/addinstance_form.php create mode 100644 enrol/meta/db/access.php create mode 100644 enrol/meta/db/events.php create mode 100644 enrol/meta/db/install.php create mode 100644 enrol/meta/lang/en/enrol_meta.php create mode 100644 enrol/meta/lib.php create mode 100644 enrol/meta/locallib.php create mode 100644 enrol/meta/settings.php create mode 100644 enrol/meta/version.php create mode 100644 enrol/otherusers.php create mode 100644 enrol/self/addinstance.php create mode 100644 enrol/self/db/access.php create mode 100644 enrol/self/db/install.php create mode 100644 enrol/self/lang/en/enrol_self.php create mode 100644 enrol/self/lib.php create mode 100644 enrol/self/locallib.php create mode 100644 enrol/self/settings.php create mode 100644 enrol/self/unenrolself.php create mode 100644 enrol/self/version.php create mode 100644 enrol/users.php create mode 100644 enrol/users_forms.php create mode 100644 lang/en/enrol.php create mode 100644 lib/enrollib.php create mode 100644 mod/assignment/db/events.php create mode 100644 mod/forum/db/events.php delete mode 100644 user/extendenrol.php delete mode 100755 user/groupextendenrol.php diff --git a/admin/bloglevelupgrade.php b/admin/bloglevelupgrade.php index f833c176915..b04d1dc46d1 100644 --- a/admin/bloglevelupgrade.php +++ b/admin/bloglevelupgrade.php @@ -48,7 +48,7 @@ if ($CFG->bloglevel == BLOG_COURSE_LEVEL || $CFG->bloglevel == BLOG_GROUP_LEVEL) $a->blogcount = 0; foreach ($bloggers as $blogger) { - $courses = get_my_courses($blogger->userid); + $courses = enrol_get_users_courses($blogger->userid, true, 'groupmode,groupmodeforce'); $blogentries = $DB->get_records('post', array('module' => 'blog', 'userid' => $blogger->userid)); foreach ($courses as $course) { diff --git a/admin/cron.php b/admin/cron.php index ef41ce01e46..79def22767d 100644 --- a/admin/cron.php +++ b/admin/cron.php @@ -205,34 +205,6 @@ } mtrace('Finished admin reports'); - mtrace('Removing expired enrolments ...', ''); // See MDL-8785 - $timenow = time(); - $somefound = false; - // The preferred way saves memory, datablib - // find courses where limited enrolment is enabled - $sql = "SELECT ra.roleid, ra.userid, ra.contextid - FROM {course} c - JOIN {context} cx ON cx.instanceid = c.id - JOIN {role_assignments} ra ON ra.contextid = cx.id - WHERE cx.contextlevel = '".CONTEXT_COURSE."' - AND ra.timeend > 0 - AND ra.timeend < ? - AND c.enrolperiod > 0"; - if ($rs = $DB->get_recordset_sql($sql, array($timenow))) { - foreach ($rs as $oldenrolment) { - role_unassign($oldenrolment->roleid, $oldenrolment->userid, 0, $oldenrolment->contextid); - $somefound = true; - } - $rs->close(); - } - if ($somefound) { - mtrace('Done'); - } else { - mtrace('none found'); - } - - - mtrace('Starting main gradebook job ...'); grade_cron(); mtrace('done.'); @@ -270,41 +242,6 @@ if ($random100 < 20) { // Approximately 20% of the time. mtrace("Running clean-up tasks..."); - /// Unenrol users who haven't logged in for $CFG->longtimenosee - - if ($CFG->longtimenosee) { // value in days - $cuttime = $timenow - ($CFG->longtimenosee * 3600 * 24); - $rs = $DB->get_recordset_sql ("SELECT id, userid, courseid - FROM {user_lastaccess} - WHERE courseid != ".SITEID." - AND timeaccess < ?", array($cuttime)); - foreach ($rs as $assign) { - if ($context = get_context_instance(CONTEXT_COURSE, $assign->courseid)) { - if (role_unassign(0, $assign->userid, 0, $context->id)) { - mtrace("removing user $assign->userid from course $assign->courseid as they have not accessed the course for over $CFG->longtimenosee days"); - } - } - } - $rs->close(); - /// Execute the same query again, looking for remaining records and deleting them - /// if the user hasn't moodle/course:participate in the CONTEXT_COURSE context (orphan records) - $rs = $DB->get_recordset_sql ("SELECT id, userid, courseid - FROM {user_lastaccess} - WHERE courseid != ".SITEID." - AND timeaccess < ?", array($cuttime)); - foreach ($rs as $assign) { - if ($context = get_context_instance(CONTEXT_COURSE, $assign->courseid)) { - if (!is_enrolled($context, $assign->userid) and !is_viewing($context, $assign->userid)) { - $DB->delete_records('user_lastaccess', array('userid'=>$assign->userid, 'courseid'=>$assign->courseid)); - mtrace("Deleted orphan user_lastaccess for user $assign->userid from course $assign->courseid"); - } - } - } - $rs->close(); - } - flush(); - - /// Delete users who haven't confirmed within required period if (!empty($CFG->deleteunconfirmed)) { @@ -370,9 +307,6 @@ } flush(); - sync_metacourses(); - mtrace('Synchronised metacourses'); - // // generate new password emails for users // @@ -464,20 +398,16 @@ unset($authplugin); } -/// Run the enrolment cron, if any - if (!($plugins = explode(',', $CFG->enrol_plugins_enabled))) { - $plugins = array($CFG->enrol); - } - require_once($CFG->dirroot .'/enrol/enrol.class.php'); - foreach ($plugins as $p) { - $enrol = enrolment_factory::factory($p); - if (method_exists($enrol, 'cron')) { - $enrol->cron(); + mtrace("Running enrol crons if required..."); + $enrols = enrol_get_plugins(true); + foreach($enrols as $ename=>$enrol) { + // do this for all plugins, disabled plugins might want to cleanup stuff such as roles + if (!$enrol->is_cron_required()) { + continue; } - if (!empty($enrol->log)) { - mtrace($enrol->log); - } - unset($enrol); + mtrace("Running cron for enrol_$ename..."); + $enrol->cron(); + $enrol->set_config('lastcron', time()); } if (!empty($CFG->enablestats) and empty($CFG->disablestatsprocessing)) { diff --git a/admin/enrol.php b/admin/enrol.php index 0bd4866c760..26e430ef8f7 100644 --- a/admin/enrol.php +++ b/admin/enrol.php @@ -1,141 +1,120 @@ . - require_once('../config.php'); - require_once($CFG->libdir.'/adminlib.php'); +/** + * Enrol config manipulation script. + * + * @package core + * @subpackage enrol + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ - $enrol = optional_param('enrol', $CFG->enrol, PARAM_SAFEDIR); - $savesettings = optional_param('savesettings', 0, PARAM_BOOL); +require_once('../config.php'); +require_once($CFG->libdir.'/adminlib.php'); - admin_externalpage_setup('enrolment'); +$action = required_param('action', PARAM_ACTION); +$enrol = required_param('enrol', PARAM_SAFEDIR); +$confirm = optional_param('confirm', 0, PARAM_BOOL); - if (!isset($CFG->sendcoursewelcomemessage)) { - set_config('sendcoursewelcomemessage', 1); - } +$PAGE->set_url('/admin/enrol.php'); +require_login(); +require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM)); +require_sesskey(); - require_once("$CFG->dirroot/enrol/enrol.class.php"); /// Open the factory class +$enabled = enrol_get_plugins(true); +$all = enrol_get_plugins(false); -/// Save settings +$return = new moodle_url('/admin/settings.php', array('section'=>'manageenrols')); - if ($frm = data_submitted() and !$savesettings) { - if (!confirm_sesskey()) { - print_error('confirmsesskeybad', 'error'); +switch ($action) { + case 'disable': + unset($enabled[$enrol]); + set_config('enrol_plugins_enabled', implode(',', array_keys($enabled))); + break; + + case 'enable': + if (!isset($all[$enrol])) { + break; } - if (empty($frm->enable)) { - $frm->enable = array(); + $enabled = array_keys($enabled); + $enabled[] = $enrol; + set_config('enrol_plugins_enabled', implode(',', $enabled)); + break; + + case 'up': + if (!isset($enabled[$enrol])) { + break; } - if (empty($frm->default)) { - $frm->default = ''; + $enabled = array_keys($enabled); + $enabled = array_flip($enabled); + $current = $enabled[$enrol]; + if ($current == 0) { + break; //already at the top } - if ($frm->default && $frm->default != 'manual' && !in_array($frm->default, $frm->enable)) { - $frm->enable[] = $frm->default; + $enabled = array_flip($enabled); + $enabled[$current] = $enabled[$current - 1]; + $enabled[$current - 1] = $enrol; + set_config('enrol_plugins_enabled', implode(',', $enabled)); + break; + + case 'down': + if (!isset($enabled[$enrol])) { + break; } - asort($frm->enable); - $frm->enable = array_merge(array('manual'), $frm->enable); // make sure manual plugin is called first - set_config('enrol_plugins_enabled', implode(',', $frm->enable)); - set_config('enrol', $frm->default); - redirect("enrol.php", get_string("changessaved"), 1); - - } else if ($frm = data_submitted() and $savesettings) { - if (!confirm_sesskey()) { - print_error('confirmsesskeybad', 'error'); + $enabled = array_keys($enabled); + $enabled = array_flip($enabled); + $current = $enabled[$enrol]; + if ($current == count($enabled) - 1) { + break; //already at the end } - set_config('sendcoursewelcomemessage', required_param('sendcoursewelcomemessage', PARAM_BOOL)); - } + $enabled = array_flip($enabled); + $enabled[$current] = $enabled[$current + 1]; + $enabled[$current + 1] = $enrol; + set_config('enrol_plugins_enabled', implode(',', $enabled)); + break; -/// Print the form + case 'uninstall': + echo $OUTPUT->header(); + echo $OUTPUT->heading(get_string('enrolments', 'enrol')); - $str = get_strings(array('enrolmentplugins', 'users', 'administration', 'settings', 'edit')); - - echo $OUTPUT->header(); - - $modules = get_plugin_list('enrol'); - $options = array(); - foreach ($modules as $module => $moduledir) { - $options[$module] = get_string("enrolname", "enrol_$module"); - } - asort($options); - - echo $OUTPUT->box(get_string('configenrolmentplugins', 'admin')); - - echo "
"; - echo "
"; - echo ""; - - $table = new html_table(); - $table->head = array(get_string('name'), get_string('enable'), get_string('default'), $str->settings); - $table->align = array('left', 'center', 'center', 'center'); - $table->size = array('60%', '', '', '15%'); - $table->attributes['class'] = 'generaltable enrolplugintable'; - $table->data = array(); - - $enabledplugins = explode(',', $CFG->enrol_plugins_enabled); - foreach ($modules as $module => $moduledir) { - - // skip if directory is empty - if (!file_exists("$moduledir/enrol.php")) { - continue; - } - - $name = get_string("enrolname", "enrol_$module"); - $plugin = enrolment_factory::factory($module); - $enable = 'enrol == $module) { - $default .= ' checked="checked"'; - } - $default .= ' />'; + if (get_string_manager()->string_exists('pluginname', 'enrol_'.$enrol)) { + $strplugin = get_string('pluginname', 'enrol_'.$enrol); } else { - $default = ''; + $strplugin = $enrol; } - $table->data[$name] = array($name, $enable, $default, - ''.$str->edit.''); - } - asort($table->data); - echo html_writer::table($table); + if (!$confirm) { + $uurl = new moodle_url('/admin/enrol.php', array('action'=>'uninstall', 'enrol'=>$enrol, 'sesskey'=>sesskey(), 'confirm'=>1)); + echo $OUTPUT->confirm(get_string('uninstallconfirm', 'enrol', $strplugin), $uurl, $return); + echo $OUTPUT->footer(); + exit; - echo "
\n"; - echo "
"; - echo "
"; + } else { // Delete everything!! + uninstall_plugin('enrol', $enrol); - echo '
'; - - $yesnooptions = array(0=>get_string('no'), 1=>get_string('yes')); - - echo '
'; - echo '
'; - echo $OUTPUT->heading(get_string('commonsettings', 'admin')); - echo ''; - echo ''; - echo '
'; - echo '
'; - - echo '
'; - echo '
'; - echo html_writer::select($yesnooptions, 'sendcoursewelcomemessage', $CFG->sendcoursewelcomemessage, false); - echo '
'.get_string('defaultsettinginfo', 'admin', get_string('yes')).'
'; - echo '
' . get_string('configsendcoursewelcomemessage', 'admin') . '
'; - echo '
'; - - echo '
'; - - echo '
'; - echo '
'; - echo '
'; - - echo $OUTPUT->footer(); + $a->plugin = $strplugin; + $a->directory = "$CFG->dirroot/enrol/$enrol"; + echo $OUTPUT->notification(get_string('uninstalldeletefiles', 'enrol', $a), 'notifysuccess'); + echo $OUTPUT->continue_button($return); + echo $OUTPUT->footer(); + exit; + } +} +redirect($return); \ No newline at end of file diff --git a/admin/enrol_config.php b/admin/enrol_config.php deleted file mode 100644 index cf8e60aee7b..00000000000 --- a/admin/enrol_config.php +++ /dev/null @@ -1,70 +0,0 @@ -libdir.'/adminlib.php'); - - admin_externalpage_setup('enrolment'); - - $enrol = required_param('enrol', PARAM_ALPHA); - $PAGE->set_pagetype('admin-enrol-' . $enrol); - - require_once("$CFG->dirroot/enrol/enrol.class.php"); /// Open the factory class - - $enrolment = enrolment_factory::factory($enrol); - -/// If data submitted, then process and store. - - if ($frm = data_submitted()) { - if (!confirm_sesskey()) { - print_error('confirmsesskeybad', 'error'); - } - if ($enrolment->process_config($frm)) { - redirect("enrol.php?sesskey=".sesskey(), get_string("changessaved"), 1); - } - } else { - $frm = $CFG; - } - -/// Otherwise fill and print the form. - - /// get language strings - $str = get_strings(array('enrolmentplugins', 'configuration', 'users', 'administration')); - - unset($options); - - $modules = get_plugin_list('enrol'); - foreach ($modules as $module => $enroldir) { - $options[$module] = get_string("enrolname", "enrol_$module"); - } - asort($options); - - echo $OUTPUT->header(); - - echo "
"; - echo "
"; - echo ""; - echo ""; - -/// Print current enrolment type description - echo $OUTPUT->box_start(); - echo $OUTPUT->heading($options[$enrol]); - - echo $OUTPUT->box_start('informationbox'); - print_string("description", "enrol_$enrol"); - echo $OUTPUT->box_end(); - - echo "
"; - - $enrolment->config_form($frm); - - echo "

\n"; - echo $OUTPUT->box_end(); - echo "
"; - echo "
"; - - echo $OUTPUT->footer(); - - exit; - diff --git a/admin/generator.php b/admin/generator.php index 315d44e9063..96e3b35b137 100755 --- a/admin/generator.php +++ b/admin/generator.php @@ -709,23 +709,16 @@ class generator { $context = get_context_instance(CONTEXT_COURSE, $courseid); foreach ($users_to_assign as $random_user) { - $success = role_assign(5, $random_user, 0, $context->id); + role_assign(5, $random_user, $context->id); - if ($success) { - $assigned_count++; - $course_users[$courseid][] = $random_user; - if (!isset($assigned_users[$random_user])) { - $assigned_users[$random_user] = 1; - } else { - $assigned_users[$random_user]++; - } - $this->verbose("Student $random_user was assigned to course $courseid."); + $assigned_count++; + $course_users[$courseid][] = $random_user; + if (!isset($assigned_users[$random_user])) { + $assigned_users[$random_user] = 1; } else { - $this->verbose("Could not assign student $random_user to course $courseid!"); - if (!$this->get('ignore_errors')) { - die(); - } + $assigned_users[$random_user]++; } + $this->verbose("Student $random_user was assigned to course $courseid."); } } diff --git a/admin/mnet/enr_course_enrol.php b/admin/mnet/enr_course_enrol.php index 6cea4621f12..6404a9994eb 100644 --- a/admin/mnet/enr_course_enrol.php +++ b/admin/mnet/enr_course_enrol.php @@ -1,7 +1,9 @@ libdir.'/adminlib.php'); include_once($CFG->dirroot.'/mnet/xmlrpc/client.php'); @@ -12,8 +14,7 @@ admin_externalpage_setup('mnetenrol'); - require_once("$CFG->dirroot/enrol/enrol.class.php"); /// Open the factory class - $enrolment = enrolment_factory::factory('mnet'); + $enrolment = enrol_get_plugin('mnet'); $mnethostid = required_param('host', PARAM_INT); $courseid = required_param('courseid', PARAM_INT); @@ -278,7 +279,7 @@ /// Print the page /// get language strings -$str = get_strings(array('enrolmentplugins', 'configuration', 'users', 'administration')); +$str = get_strings(array('configuration', 'users', 'administration')); /// Get some language strings $strpotentialusers = get_string('potentialusers', 'role'); diff --git a/admin/mnet/enr_courses.php b/admin/mnet/enr_courses.php index cee043ede11..0ca015932bb 100644 --- a/admin/mnet/enr_courses.php +++ b/admin/mnet/enr_courses.php @@ -1,7 +1,9 @@ libdir.'/adminlib.php'); require_once($CFG->dirroot.'/mnet/lib.php'); @@ -13,8 +15,7 @@ admin_externalpage_setup('mnetenrol'); - require_once("$CFG->dirroot/enrol/enrol.class.php"); /// Open the factory class - $enrolment = enrolment_factory::factory('mnet'); + $enrolment = enrol_get_plugin('mnet'); $mnethost = required_param('host', PARAM_INT); $host = $DB->get_record('mnet_host', array('id'=>$mnethost)); diff --git a/admin/mnet/enr_hosts.php b/admin/mnet/enr_hosts.php index ae964f5551e..b97ddd77995 100644 --- a/admin/mnet/enr_hosts.php +++ b/admin/mnet/enr_hosts.php @@ -6,11 +6,11 @@ require_once($CFG->libdir.'/adminlib.php'); require_once($CFG->dirroot.'/mnet/lib.php'); +die('TODO: MDL-22787 mnet enrolments are not reimplemented yet, sorry.'); + admin_externalpage_setup('mnetenrol'); - require_once("$CFG->dirroot/enrol/enrol.class.php"); /// Open the factory class - - $enrolment = enrolment_factory::factory('mnet'); + $enrolment = enrol_get_plugin('mnet'); /// Otherwise fill and print the form. diff --git a/admin/report/security/lang/en/report_security.php b/admin/report/security/lang/en/report_security.php index e8c11903ef5..e80d85f50b5 100644 --- a/admin/report/security/lang/en/report_security.php +++ b/admin/report/security/lang/en/report_security.php @@ -35,24 +35,6 @@ $string['check_cookiesecure_details'] = '

If you enable https communication it $string['check_cookiesecure_error'] = 'Please enable secure cookies'; $string['check_cookiesecure_name'] = 'Secure cookies'; $string['check_cookiesecure_ok'] = 'Secure cookies enabled.'; -$string['check_courserole_anything'] = 'The "doanything" capability must not be allowed in this context.'; -$string['check_courserole_details'] = '

Each course has one default enrolment role specified. Please make sure no risky capabilities are allowed for this role.

-

The only supported legacy type for the default course role is Student.

'; -$string['check_courserole_error'] = 'Incorrectly defined default course roles detected!'; -$string['check_courserole_name'] = 'Default roles (courses)'; -$string['check_courserole_notyet'] = 'Used only default course role.'; -$string['check_courserole_ok'] = 'Default course role definitions is OK.'; -$string['check_courserole_risky'] = 'Risky capabilities detected in context.'; -$string['check_courserole_riskylegacy'] = 'Risky legacy type detected in {$a->shortname}.'; -$string['check_defaultcourserole_anything'] = 'The "doanything" capability must not be allowed in this context.'; -$string['check_defaultcourserole_details'] = '

The default student role for course enrolment specifies the default role for courses. Please make sure no risky capabilities are allowed in this role.

-

The only supported legacy type for default role is Student.

'; -$string['check_defaultcourserole_error'] = 'Incorrectly defined default course role "{$a}" detected!'; -$string['check_defaultcourserole_legacy'] = 'Risky legacy type detected.'; -$string['check_defaultcourserole_name'] = 'Default course role (global)'; -$string['check_defaultcourserole_notset'] = 'Default role is not set.'; -$string['check_defaultcourserole_ok'] = 'Site default role definition is OK.'; -$string['check_defaultcourserole_risky'] = 'Risky capabilities detected in context.'; $string['check_defaultuserrole_details'] = '

All logged in users are given capabilities of the default user role. Please make sure no risky capabilities are allowed in this role.

The only supported legacy type for the default user role is Authenticated user. The course view capability must not be enabled.

'; $string['check_defaultuserrole_error'] = 'The default user role "{$a}" is incorrectly defined!'; diff --git a/admin/report/security/lib.php b/admin/report/security/lib.php index 2d59c764369..b3053ffab8f 100644 --- a/admin/report/security/lib.php +++ b/admin/report/security/lib.php @@ -58,8 +58,6 @@ function report_security_get_issue_list() { 'report_security_check_defaultuserrole', 'report_security_check_guestrole', 'report_security_check_frontpagerole', - 'report_security_check_defaultcourserole', - 'report_security_check_courserole', ); } @@ -587,9 +585,6 @@ function report_security_check_defaultuserrole($detailed=false) { $riskycount = $DB->count_records_sql($sql, $params); - // default role can not have view cap in all courses - this would break moodle badly - $viewcap = $DB->record_exists('role_capabilities', array('roleid'=>$default_role->id, 'permission'=>CAP_ALLOW, 'capability'=>'moodle/course:participate')); - // it may have either none or 'user' archetype - nothing else, or else it would break during upgrades badly if ($default_role->archetype === '' or $default_role->archetype === 'user') { $legacyok = true; @@ -597,7 +592,7 @@ function report_security_check_defaultuserrole($detailed=false) { $legacyok = false; } - if ($riskycount or $viewcap or !$legacyok) { + if ($riskycount or !$legacyok) { $result->status = REPORT_SECURITY_CRITICAL; $result->info = get_string('check_defaultuserrole_error', 'report_security', format_string($default_role->name)); @@ -730,190 +725,6 @@ function report_security_check_frontpagerole($detailed=false) { return $result; } -/** - * Verifies sanity of site default course role. - * @param bool $detailed - * @return object result - */ -function report_security_check_defaultcourserole($detailed=false) { - global $DB, $CFG; - - $problems = array(); - - $result = new object(); - $result->issue = 'report_security_check_defaultcourserole'; - $result->name = get_string('check_defaultcourserole_name', 'report_security'); - $result->info = null; - $result->details = null; - $result->status = null; - $result->link = "wwwroot/$CFG->admin/settings.php?section=userpolicies\">".get_string('userpolicies', 'admin').'';; - - if ($detailed) { - $result->details = get_string('check_defaultcourserole_details', 'report_security'); - } - - if (!$student_role = $DB->get_record('role', array('id'=>$CFG->defaultcourseroleid))) { - $result->status = REPORT_SECURITY_WARNING; - $result->info = get_string('check_defaultcourserole_notset', 'report_security'); - $result->details = get_string('check_defaultcourserole_details', 'report_security'); - - return $result; - } - - // risky caps - usually very dangerous - $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$student_role->id); - $sql = "SELECT DISTINCT rc.contextid - FROM {role_capabilities} rc - JOIN {capabilities} cap ON cap.name = rc.capability - WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))." <> 0 - AND rc.permission = :capallow - AND rc.roleid = :roleid"; - - if ($riskycontexts = $DB->get_records_sql($sql, $params)) { - foreach($riskycontexts as $contextid=>$unused) { - if ($contextid == SYSCONTEXTID) { - $a = "$CFG->wwwroot/$CFG->admin/roles/define.php?action=view&roleid=$CFG->defaultcourseroleid"; - } else { - $a = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid&roleid=$CFG->defaultcourseroleid"; - } - $problems[] = get_string('check_defaultcourserole_risky', 'report_security', $a); - } - } - - // course creator or administrator does not make any sense here - if ($student_role->archetype === 'coursecreator' or $student_role->archetype === 'manager') { - $problems[] = get_string('check_defaultcourserole_legacy', 'report_security'); - } - - if ($problems) { - $result->status = REPORT_SECURITY_CRITICAL; - $result->info = get_string('check_defaultcourserole_error', 'report_security', format_string($student_role->name)); - if ($detailed) { - $result->details .= ""; - } - - } else { - $result->status = REPORT_SECURITY_OK; - $result->info = get_string('check_defaultcourserole_ok', 'report_security'); - } - - return $result; -} - -/** - * Verifies sanity of default roles in courses. - * @param bool $detailed - * @return object result - */ -function report_security_check_courserole($detailed=false) { - global $DB, $CFG, $SITE; - - $problems = array(); - - $result = new object(); - $result->issue = 'report_security_check_courserole'; - $result->name = get_string('check_courserole_name', 'report_security'); - $result->info = null; - $result->details = null; - $result->status = null; - $result->link = null; - - if ($detailed) { - $result->details = get_string('check_courserole_details', 'report_security'); - } - - // get list of all student roles selected in courses excluding the default course role - $params = array('siteid'=>$SITE->id, 'defaultcourserole'=>$CFG->defaultcourseroleid); - $sql = "SELECT r.* - FROM {role} r - JOIN {course} c ON c.defaultrole = r.id - WHERE c.id <> :siteid AND r.id <> :defaultcourserole"; - - if (!$student_roles = $DB->get_records_sql($sql, $params)) { - $result->status = REPORT_SECURITY_OK; - $result->info = get_string('check_courserole_notyet', 'report_security'); - $result->details = get_string('check_courserole_details', 'report_security'); - - return $result; - } - - $roleids = array_keys($student_roles); - - $sql = "SELECT DISTINCT rc.roleid - FROM {role_capabilities} rc - JOIN {role} r ON r.id = rc.roleid - WHERE (r.archetype = :coursecreator OR r.archetype = :teacher OR r.archetype = :editingteacher OR r.archetype = :manager)"; - $params = array('coursecreator' => 'coursecreator', - 'teacher' => 'teacher', - 'editingteacher' => 'editingteacher', - 'manager' => 'manager'); - - $riskyroleids = $DB->get_records_sql($sql, $params); - $riskyroleids = array_keys($riskyroleids); - - // any XSS legacy cap does not make any sense here! - list($inroles, $params) = $DB->get_in_or_equal($roleids, SQL_PARAMS_NAMED, 'r0', true); - $sql = "SELECT DISTINCT c.id, c.shortname - FROM {course} c - WHERE c.defaultrole $inroles - ORDER BY c.sortorder"; - if ($courses = $DB->get_records_sql($sql, $params)) { - foreach ($courses as $course) { - $a = (object)array('url'=>"$CFG->wwwroot/course/edit.php?id=$course->id", 'shortname'=>$course->shortname); - $problems[] = get_string('check_courserole_riskylegacy', 'report_security', $a); - } - } - - // risky caps in any level - usually very dangerous!! - if ($checkroles = array_diff($roleids, $riskyroleids)) { - list($inroles, $params) = $DB->get_in_or_equal($checkroles, SQL_PARAMS_NAMED, 'r0', true); - $params = array_merge($params, array('capallow'=>CAP_ALLOW)); - $sql = "SELECT rc.roleid, rc.contextid - FROM {role_capabilities} rc - JOIN {capabilities} cap ON cap.name = rc.capability - WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))." <> 0 - AND rc.permission = :capallow - AND rc.roleid $inroles - GROUP BY rc.roleid, rc.contextid - ORDER BY rc.roleid, rc.contextid"; - $rs = $DB->get_recordset_sql($sql, $params); - foreach($rs as $res) { - $roleid = $res->roleid; - $contextid = $res->contextid; - if ($contextid == SYSCONTEXTID) { - $a = "$CFG->wwwroot/$CFG->admin/roles/define.php?action=view&roleid=$roleid"; - } else { - $a = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid&roleid=$roleid"; - } - $problems[] = get_string('check_courserole_risky', 'report_security', $a); - } - $rs->close(); - } - - - if ($problems) { - $result->status = REPORT_SECURITY_CRITICAL; - $result->info = get_string('check_courserole_error', 'report_security'); - if ($detailed) { - $result->details .= ""; - } - - } else { - $result->status = REPORT_SECURITY_OK; - $result->info = get_string('check_courserole_ok', 'report_security'); - } - - return $result; -} - /** * Lists all admins. * @param bool $detailed diff --git a/admin/roles/assign.php b/admin/roles/assign.php index a03840b1bb5..6b17a602277 100755 --- a/admin/roles/assign.php +++ b/admin/roles/assign.php @@ -31,8 +31,6 @@ define("MAX_USERS_TO_LIST_PER_ROLE", 10); $contextid = required_param('contextid',PARAM_INT); $roleid = optional_param('roleid', 0, PARAM_INT); -$extendperiod = optional_param('extendperiod', 0, PARAM_INT); -$extendbase = optional_param('extendbase', 3, PARAM_INT); list($context, $course, $cm) = get_context_info_array($contextid); @@ -58,7 +56,6 @@ $PAGE->set_context($context); $contextname = print_context_name($context); $courseid = $course->id; -$inmeta = $course->metacourse; $isfrontpage = ($course->id == SITEID); // These are needed early because of tabs.php @@ -87,40 +84,6 @@ if ($roleid) { } } -// Build the list of options for the enrolment period dropdown. -$unlimitedperiod = get_string('unlimited'); -for ($i=1; $i<=365; $i++) { - $seconds = $i * 86400; - $periodmenu[$seconds] = get_string('numdays', '', $i); -} -// Work out the apropriate default setting. -if ($extendperiod) { - $defaultperiod = $extendperiod; -} else { - $defaultperiod = $course->enrolperiod; -} - -// Build the list of options for the starting from dropdown. -$timeformat = get_string('strftimedatefullshort'); -$today = time(); -$today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0); - -// MDL-12420, preventing course start date showing up as an option at system context and front page roles. -if ($course->startdate > 0) { - $basemenu[2] = get_string('coursestart') . ' (' . userdate($course->startdate, $timeformat) . ')'; -} -if ($course->enrollable != 2 || ($course->enrolstartdate == 0 || $course->enrolstartdate <= $today) && ($course->enrolenddate == 0 || $course->enrolenddate > $today)) { - $basemenu[3] = get_string('today') . ' (' . userdate($today, $timeformat) . ')' ; -} -if ($course->enrollable == 2) { - if($course->enrolstartdate > 0) { - $basemenu[4] = get_string('courseenrolstart') . ' (' . userdate($course->enrolstartdate, $timeformat) . ')'; - } - if($course->enrolenddate > 0) { - $basemenu[5] = get_string('courseenrolend') . ' (' . userdate($course->enrolenddate, $timeformat) . ')'; - } -} - // Process any incoming role assignments before printing the header. if ($roleid) { @@ -138,46 +101,9 @@ if ($roleid) { foreach ($userstoassign as $adduser) { $allow = true; - if ($inmeta) { - if (has_capability('moodle/course:managemetacourse', $context, $adduser->id)) { - //ok - } else { - $managerroles = get_roles_with_capability('moodle/course:managemetacourse', CAP_ALLOW, $context); - if (!empty($managerroles) and !array_key_exists($roleid, $managerroles)) { - $erruser = $DB->get_record('user', array('id'=>$adduser->id), 'id, firstname, lastname'); - $errors[] = get_string('metaassignerror', 'role', fullname($erruser)); - $allow = false; - } - } - } if ($allow) { - switch($extendbase) { - case 2: - $timestart = $course->startdate; - break; - case 3: - $timestart = $today; - break; - case 4: - $timestart = $course->enrolstartdate; - break; - case 5: - $timestart = $course->enrolenddate; - break; - } - - if($extendperiod > 0) { - $timeend = $timestart + $extendperiod; - } else { - $timeend = 0; - } - if (! role_assign($roleid, $adduser->id, 0, $context->id, $timestart, $timeend)) { - $a = new stdClass; - $a->role = $assignableroles[$roleid]; - $a->user = fullname($adduser); - $errors[] = get_string('assignerror', 'role', $a); - } + role_assign($roleid, $adduser->id, $context->id); } } @@ -197,18 +123,8 @@ if ($roleid) { if (!empty($userstounassign)) { foreach ($userstounassign as $removeuser) { - if (! role_unassign($roleid, $removeuser->id, 0, $context->id)) { - $a = new stdClass; - $a->role = $assignableroles[$roleid]; - $a->user = fullname($removeuser); - $errors[] = get_string('unassignerror', 'role', $a); - } else if ($inmeta) { - sync_metacourse($courseid); - $newroles = get_user_roles($context, $removeuser->id, false); - if (empty($newroles) || array_key_exists($roleid, $newroles)) { - $errors[] = get_string('metaunassignerror', 'role', fullname($removeuser)); - } - } + //unassign only roles that are added manually, no messing with other components!!! + role_unassign($roleid, $removeuser->id, $context->id, ''); } $potentialuserselector->invalidate_selected_users(); @@ -224,14 +140,12 @@ if ($roleid) { $PAGE->set_pagelayout('admin'); $PAGE->set_title($title); -$tabfile = $CFG->dirroot.'/'.$CFG->admin.'/roles/tabs.php'; switch ($context->contextlevel) { case CONTEXT_SYSTEM: admin_externalpage_setup('assignroles', '', array('contextid' => $contextid, 'roleid' => $roleid)); break; case CONTEXT_USER: - $tabfile = null; if ($isfrontpage) { $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context)); $PAGE->set_heading($fullname); @@ -260,10 +174,6 @@ switch ($context->contextlevel) { } echo $OUTPUT->header(); -if ($tabfile) { - $currenttab = 'assign'; - include($tabfile); -} // Print heading. echo $OUTPUT->heading_with_help($title, 'assignroles', 'role'); @@ -290,16 +200,6 @@ $assignurl = new moodle_url($PAGE->url, array('roleid'=>$roleid));

- - - -


-

- -


-

-
@@ -352,11 +252,6 @@ $assignurl = new moodle_url($PAGE->url, array('roleid'=>$roleid)); // Print instruction echo $OUTPUT->heading(get_string('chooseroletoassign', 'role'), 3); - // sync metacourse enrolments if needed - if ($inmeta) { - sync_metacourse($course); - } - // Get the names of role holders for roles with between 1 and MAX_USERS_TO_LIST_PER_ROLE users, // and so determine whether to show the extra column. $roleholdernames = array(); diff --git a/admin/roles/check.php b/admin/roles/check.php index cad9fe512d9..27ebd970c21 100755 --- a/admin/roles/check.php +++ b/admin/roles/check.php @@ -73,14 +73,12 @@ $title = get_string('checkpermissionsin', 'role', $contextname); $PAGE->set_pagelayout('admin'); $PAGE->set_title($title); -$tabfile = $CFG->dirroot.'/'.$CFG->admin.'/roles/tabs.php'; switch ($context->contextlevel) { case CONTEXT_SYSTEM: - admin_externalpage_setup('assignroles', '', array('contextid' => $contextid, 'roleid' => $roleid)); + admin_externalpage_setup('assignroles', '', array('contextid' => $contextid)); break; case CONTEXT_USER: - $tabfile = null; if ($isfrontpage) { $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context)); $PAGE->set_heading($fullname); @@ -112,10 +110,6 @@ echo $OUTPUT->header(); // These are needed early because of tabs.php $assignableroles = get_assignable_roles($context, ROLENAME_BOTH); $overridableroles = get_overridable_roles($context, ROLENAME_BOTH); -if ($tabfile) { - $currenttab = 'check'; - include($tabfile); -} // Print heading. echo $OUTPUT->heading($title); diff --git a/admin/roles/lib.php b/admin/roles/lib.php index 203abc8b352..33493acdd51 100644 --- a/admin/roles/lib.php +++ b/admin/roles/lib.php @@ -1020,56 +1020,27 @@ abstract class role_assign_user_selector_base extends user_selector_base { * when we are assigning in a context below the course level. (CONTEXT_MODULE and * some CONTEXT_BLOCK). * - * In this case we replicate part of get_users_by_capability() get the users - * with moodle/course:participate. We can't use - * get_users_by_capability() becuase - * 1) get_users_by_capability() does not deal with searching by name - * 2) exceptions array can be potentially large for large courses + * This returns only enrolled users in this context. */ class potential_assignees_below_course extends role_assign_user_selector_base { public function find_users($search) { global $DB; - // Get roles with some assignement to the 'moodle/course:participate' capability. - $possibleroles = get_roles_with_capability('moodle/course:participate', CAP_ALLOW, $this->context); - if (empty($possibleroles)) { - // If there aren't any, we are done. - return array(); - } - - // Now exclude the admin roles, and check the actual permission on - // 'moodle/course:participate' to make sure it is allow. - $validroleids = array(); - - foreach ($possibleroles as $possiblerole) { - if ($caps = role_context_capabilities($possiblerole->id, $this->context, 'moodle/course:participate')) { // resolved list - if (isset($caps['moodle/course:participate']) && $caps['moodle/course:participate'] > 0) { // resolved capability > 0 - $validroleids[] = $possiblerole->id; - } - } - } - - // If there are no valid roles, we are done. - if (!$validroleids) { - return array(); - } + list($enrolsql, $eparams) = get_enrolled_sql($this->context); // Now we have to go to the database. list($wherecondition, $params) = $this->search_sql($search, 'u'); + $params = array_merge($params, $eparams); + if ($wherecondition) { $wherecondition = ' AND ' . $wherecondition; } - $roleids = '('.implode(',', $validroleids).')'; - $fields = 'SELECT DISTINCT ' . $this->required_fields_sql('u'); - $countfields = 'SELECT COUNT(DISTINCT u.id)'; + $fields = 'SELECT ' . $this->required_fields_sql('u'); + $countfields = 'SELECT COUNT(u.id)'; $sql = " FROM {user} u - JOIN {role_assignments} ra ON ra.userid = u.id - JOIN {role} r ON r.id = ra.roleid - WHERE ra.contextid " . get_related_contexts_string($this->context)." - $wherecondition - AND ra.roleid IN $roleids + WHERE u.id IN ($enrolsql) $wherecondition AND u.id NOT IN ( SELECT u.id FROM {role_assignments} r, {user} u @@ -1174,7 +1145,7 @@ class existing_role_holders extends role_assign_user_selector_base { $params = array_merge($params, $ctxparams); $params['roleid'] = $this->roleid; - $sql = "SELECT ra.id as raid," . $this->required_fields_sql('u') . ",ra.contextid + $sql = "SELECT ra.id as raid," . $this->required_fields_sql('u') . ",ra.contextid,ra.component FROM {role_assignments} ra JOIN {user} u ON u.id = ra.userid JOIN {context} ctx ON ra.contextid = ctx.id @@ -1182,7 +1153,7 @@ class existing_role_holders extends role_assign_user_selector_base { $wherecondition AND ctx.id $ctxcondition AND ra.roleid = :roleid - ORDER BY ctx.depth DESC, u.lastname, u.firstname"; + ORDER BY ctx.depth DESC, ra.component, u.lastname, u.firstname"; $contextusers = $DB->get_records_sql($sql, $params); // No users at all. @@ -1196,6 +1167,7 @@ class existing_role_holders extends role_assign_user_selector_base { $dummyuser = new stdClass; $dummyuser->contextid = 0; $dummyuser->id = 0; + $dummyuser->component = ''; $contextusers[] = $dummyuser; $results = array(); // The results array we are building up. $doneusers = array(); // Ensures we only list each user at most once. @@ -1223,6 +1195,11 @@ class existing_role_holders extends role_assign_user_selector_base { if ($currentcontextid != $this->context->id) { $user->disabled = true; } + if ($user->component !== '') { + // bad luck, you can tweak only manual role assignments + $user->disabled = true; + } + unset($user->component); $currentgroup[$user->id] = $user; } @@ -1465,8 +1442,9 @@ class role_allow_switch_page extends role_allow_role_page { } protected function load_required_roles() { + global $DB; parent::load_required_roles(); - $this->allowedtargetroles = get_allowed_switchable_roles(); + $this->allowedtargetroles = $DB->get_records_menu('roles', NULL, 'id', 'roleid, 1'); } protected function set_allow($fromroleid, $targetroleid) { diff --git a/admin/roles/manage.php b/admin/roles/manage.php index c0a946bc910..f9b09355375 100755 --- a/admin/roles/manage.php +++ b/admin/roles/manage.php @@ -60,7 +60,6 @@ $undeletableroles[$CFG->notloggedinroleid] = 1; $undeletableroles[$CFG->guestroleid] = 1; $undeletableroles[$CFG->defaultuserroleid] = 1; - $undeletableroles[$CFG->defaultcourseroleid] = 1; ///.Process submitted data. $confirmed = optional_param('confirm', false, PARAM_BOOL) && data_submitted() && confirm_sesskey(); diff --git a/admin/roles/override.php b/admin/roles/override.php index 2d21254a914..29737d5226a 100755 --- a/admin/roles/override.php +++ b/admin/roles/override.php @@ -65,7 +65,7 @@ if (optional_param('cancel', false, PARAM_BOOL)) { $role = $DB->get_record('role', array('id'=>$roleid), '*', MUST_EXIST); -// These are needed early +// These are needed early $assignableroles = get_assignable_roles($context, ROLENAME_BOTH); list($overridableroles, $overridecounts, $nameswithcounts) = get_overridable_roles($context, ROLENAME_BOTH, true); @@ -75,7 +75,6 @@ $straction = get_string('overrideroles', 'role'); // Used by tabs.php $a = (object)array('context' => $contextname, 'role' => $overridableroles[$roleid]); $title = get_string('overridepermissionsforrole', 'role', $a); -$tabfile = $CFG->dirroot.'/'.$CFG->admin.'/roles/tabs.php'; $currenttab = 'permissions'; $PAGE->set_pagelayout('admin'); @@ -86,7 +85,6 @@ switch ($context->contextlevel) { print_error('cannotoverridebaserole', 'error'); break; case CONTEXT_USER: - $tabfile = null; if ($isfrontpage) { $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context)); $PAGE->set_heading($fullname); @@ -135,9 +133,6 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) { // Finally start page output echo $OUTPUT->header(); -if ($tabfile) { - include($tabfile); -} echo $OUTPUT->heading_with_help($title, 'overridepermissions', 'role'); // Show UI for overriding roles. @@ -152,7 +147,7 @@ if (!empty($capabilities)) { echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'sesskey', 'value'=>sesskey())); echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'roleid', 'value'=>$roleid)); echo html_writer::tag('p', get_string('highlightedcellsshowinherit', 'role'), array('class'=>'overridenotice')); - + $overridestable->display(); if ($overridestable->has_locked_capabiltites()) { echo '

' . get_string('safeoverridenotice', 'role') . "

\n"; diff --git a/admin/roles/permissions.php b/admin/roles/permissions.php index cbd2ee6c0ff..bfdd1375943 100644 --- a/admin/roles/permissions.php +++ b/admin/roles/permissions.php @@ -75,7 +75,6 @@ $allowsafeoverrides = has_capability('moodle/role:safeoverride', $context); $contextname = print_context_name($context); $title = get_string('permissionsincontext', 'role', $contextname); $straction = get_string('permissions', 'role'); // Used by tabs.php -$tabfile = $CFG->dirroot.'/'.$CFG->admin.'/roles/tabs.php'; $currenttab = 'permissions'; $PAGE->set_pagelayout('admin'); @@ -85,7 +84,6 @@ switch ($context->contextlevel) { print_error('cannotoverridebaserole', 'error'); break; case CONTEXT_USER: - $tabfile = null; if ($isfrontpage) { $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context)); $PAGE->set_heading($fullname); @@ -143,9 +141,6 @@ if ($capability && ($allowoverrides || ($allowsafeoverrides && is_safe_capabilit } // Display and print echo $OUTPUT->header(); - if ($tabfile) { - include($tabfile); - } echo $OUTPUT->heading($title); echo $OUTPUT->confirm($message, $continueurl, $PAGE->url); echo $OUTPUT->footer(); @@ -184,9 +179,6 @@ if ($capability && ($allowoverrides || ($allowsafeoverrides && is_safe_capabilit } } echo $OUTPUT->header(); - if ($tabfile) { - include($tabfile); - } echo $OUTPUT->heading($title); echo $OUTPUT->box($message); $mform->display(); @@ -196,9 +188,6 @@ if ($capability && ($allowoverrides || ($allowsafeoverrides && is_safe_capabilit } echo $OUTPUT->header(); -if ($tabfile) { - include($tabfile); -} echo $OUTPUT->heading($title); $table = new permissions_table($context, $contextname, $allowoverrides, $allowsafeoverrides, $overridableroles); diff --git a/admin/roles/tabs.php b/admin/roles/tabs.php deleted file mode 100755 index 6c69a06efb9..00000000000 --- a/admin/roles/tabs.php +++ /dev/null @@ -1,116 +0,0 @@ -. - -/** - * Handles headers and tabs for the roles control at any level apart from SYSTEM level - * We assume that $currenttab, $assignableroles and $overridableroles are defined - * - * @package moodlecore - * @subpackage role - * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -if (!defined('MOODLE_INTERNAL')) { - die('Direct access to this script is forbidden.'); // It must be included from a Moodle page -} - -if (!isset($availablefilters)) { - $availablefilters = array(); - if (in_array($context->contextlevel, array(CONTEXT_COURSECAT, CONTEXT_COURSE, CONTEXT_MODULE)) && - !($context->contextlevel == CONTEXT_COURSE && $context->instanceid == SITEID) && - has_capability('moodle/filter:manage', $context)) { - $availablefilters = filter_get_available_in_context($context); - } -} - -$toprow = array(); -$inactive = array(); -$activetwo = array(); -$secondrow = array(); - -$permissionsrow = array(); - -if ($context->contextlevel != CONTEXT_SYSTEM) { // Print tabs for anything except SYSTEM context - - if ($context->contextlevel == CONTEXT_MODULE) { // Only show update button if module - $url = new moodle_url('/course/mod.php', array('update'=>$context->instanceid, 'return'=>'true', 'sesskey'=>sesskey())); - $toprow[] = new tabobject('update', $url, get_string('settings')); - } - - if (!empty($assignableroles) || $currenttab=='assign') { - $url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$context->id)); - $toprow[] = new tabobject('assign', $url, get_string('localroles', 'role'), '', true); - } - - if (has_capability('moodle/role:review', $context) or !empty($overridableroles)) { - $url = new moodle_url('/admin/roles/permissions.php', array('contextid'=>$context->id)); - $permissionsrow['permissions'] = new tabobject('permissions', $url, get_string('permissions', 'role'), '', true); - } - - if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override', 'moodle/role:assign'), $context)) { - $url = new moodle_url('/admin/roles/check.php', array('contextid'=>$context->id)); - $permissionsrow['check'] = new tabobject('check', $url, get_string('checkpermissions', 'role')); - } - - if ($permissionsrow) { - $firstpermissionrow = reset($permissionsrow); - $toprow[] = new tabobject('toppermissions', $firstpermissionrow->link, get_string('permissions', 'role'), '', true); - if (!empty($permissionsrow[$currenttab])) { - $secondrow = array_values($permissionsrow); - $inactive = array('toppermissions'); - $activetwo = array('toppermissions'); - } - } - - if (!empty($availablefilters)) { - $url = new moodle_url('/filter/manage.php', array('contextid'=>$context->id)); - $toprow[] = new tabobject('filters', $url, get_string('filters', 'admin')); - } -} -unset($permissionsrow); - -/// Here other core tabs should go (always calling tabs.php files) -/// All the logic to decide what to show must be self-contained in the tabs file -/// eg: -/// include_once($CFG->dirroot . '/grades/tabs.php'); - -/// Finally, we support adding some 'on-the-fly' tabs here -/// All the logic to decide what to show must be self-cointained in the tabs file -if (!empty($CFG->extratabs)) { - if ($extratabs = explode(',', $CFG->extratabs)) { - asort($extratabs); - foreach($extratabs as $extratab) { - /// Each extra tab must be one $CFG->dirroot relative file - if (file_exists($CFG->dirroot . '/' . $extratab)) { - include($CFG->dirroot . '/' . $extratab); - } - } - } -} - -$inactive[] = $currenttab; - -$tabs = array($toprow); - -/// If there are any secondrow defined, let's introduce it -if (!empty($secondrow)) { - $tabs[] = $secondrow; -} - -print_tabs($tabs, $currenttab, $inactive, $activetwo); - diff --git a/admin/roles/usersroles.php b/admin/roles/usersroles.php index a25d6ddbde7..7412c89f14f 100644 --- a/admin/roles/usersroles.php +++ b/admin/roles/usersroles.php @@ -55,7 +55,7 @@ if (!$canview) { /// Now get the role assignments for this user. $sql = "SELECT - ra.id, ra.userid, ra.contextid, ra.roleid, ra.enrol, + ra.id, ra.userid, ra.contextid, ra.roleid, ra.component, ra.itemid c.path, r.name AS rolename, COALESCE(rn.name, r.name) AS localname diff --git a/admin/settings/appearance.php b/admin/settings/appearance.php index 464784232d9..65106dc0f56 100644 --- a/admin/settings/appearance.php +++ b/admin/settings/appearance.php @@ -135,9 +135,9 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page $temp = new admin_externalpage('profilepage', get_string('myprofile', 'admin'), $CFG->wwwroot . '/user/profilesys.php'); $ADMIN->add('appearance', $temp); - // coursemanager is the person responsible for course - usually manages enrolments, receives notification, etc. - $temp = new admin_settingpage('coursemanager', get_string('coursemanager', 'admin')); - $temp->add(new admin_setting_special_coursemanager()); + // coursecontact is the person responsible for course - usually manages enrolments, receives notification, etc. + $temp = new admin_settingpage('coursecontact', get_string('coursecontact', 'admin')); + $temp->add(new admin_setting_special_coursecontact()); $ADMIN->add('appearance', $temp); $temp = new admin_settingpage('ajax', get_string('ajaxuse')); diff --git a/admin/settings/courses.php b/admin/settings/courses.php index e1e7504dbd8..29194139547 100644 --- a/admin/settings/courses.php +++ b/admin/settings/courses.php @@ -11,8 +11,6 @@ if ($hassiteconfig $ADMIN->add('courses', new admin_externalpage('coursemgmt', get_string('coursemgmt', 'admin'), $CFG->wwwroot . '/course/index.php?categoryedit=on', array('moodle/category:manage', 'moodle/course:create'))); - $ADMIN->add('courses', new admin_enrolment_page()); - /// Course Default Settings Page /// NOTE: these settings must be applied after all other settings because they depend on them ///main course settings @@ -41,45 +39,6 @@ if ($hassiteconfig $choices = get_max_upload_sizes(); } $temp->add(new admin_setting_configselect('moodlecourse/maxbytes', get_string('maximumupload'), get_string('coursehelpmaximumupload'), key($choices), $choices)); - $temp->add(new admin_setting_configselect('moodlecourse/metacourse', get_string('metacourse'), get_string('coursehelpmetacourse'), 0,array(0 => get_string('no'), 1 => get_string('yes')))); - - ///enrolement course settings - $temp->add(new admin_setting_heading('enrolhdr', get_string('enrolments'), '')); - require_once($CFG->dirroot.'/enrol/enrol.class.php'); - $choices = array(); - $modules = explode(',', $CFG->enrol_plugins_enabled); - foreach ($modules as $module) { - $name = get_string('enrolname', "enrol_$module"); - $plugin = enrolment_factory::factory($module); - if (method_exists($plugin, 'print_entry')) { - $choices[$name] = $module; - } - } - asort($choices); - $choices = array_flip($choices); - $choices = array_merge(array('' => get_string('sitedefault').' ('.get_string('enrolname', "enrol_$CFG->enrol").')'), $choices); - $temp->add(new admin_setting_configselect('moodlecourse/enrol', get_string('enrolmentplugins'), get_string('coursehelpenrolmentplugins'), key($choices),$choices)); - $choices = array(0 => get_string('no'), 1 => get_string('yes'), 2 => get_string('enroldate')); - $temp->add(new admin_setting_configselect('moodlecourse/enrollable', get_string('enrollable'), get_string('coursehelpenrollable'), 1,$choices)); - $periodmenu=array(); - $periodmenu[0] = get_string('unlimited'); - for ($i=1; $i<=365; $i++) { - $seconds = $i * 86400; - $periodmenu[$seconds] = get_string('numdays', '', $i); - } - $temp->add(new admin_setting_configselect('moodlecourse/enrolperiod', get_string('enrolperiod'), '', 0,$periodmenu)); - - /// - $temp->add(new admin_setting_heading('expirynotifyhdr', get_string('expirynotify'), '')); - $temp->add(new admin_setting_configselect('moodlecourse/expirynotify', get_string('notify'), get_string('coursehelpnotify'), 0,array(0 => get_string('no'), 1 => get_string('yes')))); - $temp->add(new admin_setting_configselect('moodlecourse/notifystudents', get_string('expirynotifystudents'), get_string('coursehelpexpirynotifystudents'), 0,array(0 => get_string('no'), 1 => get_string('yes')))); - $thresholdmenu=array(); - for ($i=1; $i<=30; $i++) { - $seconds = $i * 86400; - $thresholdmenu[$seconds] = get_string('numdays', '', $i); - } - $temp->add(new admin_setting_configselect('moodlecourse/expirythreshold', get_string('expirythreshold'), get_string('coursehelpexpirythreshold'), 10 * 86400,$thresholdmenu)); - $temp->add(new admin_setting_heading('groups', get_string('groups', 'group'), '')); $choices = array(); @@ -95,12 +54,6 @@ if ($hassiteconfig $choices['0'] = get_string('courseavailablenot'); $choices['1'] = get_string('courseavailable'); $temp->add(new admin_setting_configselect('moodlecourse/visible', get_string('visible'), '', 1,$choices)); - $temp->add(new admin_setting_configpasswordunmask('moodlecourse/enrolpassword', get_string('enrolmentkey'), get_string('coursehelpenrolmentkey'),'')); - $choices = array(); - $choices['0'] = get_string('guestsno'); - $choices['1'] = get_string('guestsyes'); - $choices['2'] = get_string('guestskey'); - $temp->add(new admin_setting_configselect('moodlecourse/guest', get_string('opentoguests'), '', 0,$choices)); $temp->add(new admin_setting_heading('language', get_string('language'), '')); @@ -151,7 +104,6 @@ if ($hassiteconfig $temp = new admin_settingpage('scheduled', get_string('scheduledsettings','backup'), 'moodle/backup:backupcourse'); $temp->add(new admin_setting_configcheckbox('backup/backup_sche_modules', get_string('includemodules'), get_string('backupincludemoduleshelp'), 0)); $temp->add(new admin_setting_configcheckbox('backup/backup_sche_withuserdata', get_string('includemoduleuserdata'), get_string('backupincludemoduleuserdatahelp'), 0)); - $temp->add(new admin_setting_configcheckbox('backup/backup_sche_metacourse', get_string('metacourse'), get_string('backupmetacoursehelp'), 0)); $temp->add(new admin_setting_configselect('backup/backup_sche_users', get_string('users'), get_string('backupusershelp'), 0, array(0 => get_string('all'), 1 => get_string('course')))); $temp->add(new admin_setting_configcheckbox('backup/backup_sche_logs', get_string('logs'), get_string('backuplogshelp'), 0)); diff --git a/admin/settings/frontpage.php b/admin/settings/frontpage.php index 24a537689fe..052611b24b4 100644 --- a/admin/settings/frontpage.php +++ b/admin/settings/frontpage.php @@ -50,7 +50,6 @@ if (!during_initial_install()) { //do not use during installation $temp->add(new admin_setting_configtext('commentsperpage', get_string('commentsperpage', 'admin'), '', 15, PARAM_INT)); $temp->add(new admin_setting_configtext('coursesperpage', get_string('coursesperpage', 'admin'), get_string('configcoursesperpage', 'admin'), 20, PARAM_INT)); - $temp->add(new admin_setting_configcheckbox('allowvisiblecoursesinhiddencategories', get_string('allowvisiblecoursesinhiddencategories', 'admin'), get_string('configvisiblecourses', 'admin'), 0)); // front page default role $roleoptions = array(0=>get_string('none')); // roles to choose from diff --git a/admin/settings/plugins.php b/admin/settings/plugins.php index cf77a1cf0f0..6168fff65ce 100644 --- a/admin/settings/plugins.php +++ b/admin/settings/plugins.php @@ -50,6 +50,84 @@ if ($hassiteconfig) { } } + // authentication plugins + $ADMIN->add('modules', new admin_category('authsettings', get_string('authentication', 'admin'))); + + $temp = new admin_settingpage('manageauths', get_string('authsettings', 'admin')); + $temp->add(new admin_setting_manageauths()); + $temp->add(new admin_setting_heading('manageauthscommonheading', get_string('commonsettings', 'admin'), '')); + $temp->add(new admin_setting_special_registerauth()); + $temp->add(new admin_setting_configselect('guestloginbutton', get_string('guestloginbutton', 'auth'), + get_string('showguestlogin', 'auth'), '1', array('0'=>get_string('hide'), '1'=>get_string('show')))); + $temp->add(new admin_setting_configtext('alternateloginurl', get_string('alternateloginurl', 'auth'), + get_string('alternatelogin', 'auth', htmlspecialchars(get_login_url())), '')); + $temp->add(new admin_setting_configtext('forgottenpasswordurl', get_string('forgottenpasswordurl', 'auth'), + get_string('forgottenpassword', 'auth'), '')); + $temp->add(new admin_setting_confightmleditor('auth_instructions', get_string('instructions', 'auth'), + get_string('authinstructions', 'auth'), '')); + $temp->add(new admin_setting_configtext('allowemailaddresses', get_string('allowemailaddresses', 'admin'), get_string('configallowemailaddresses', 'admin'), '', PARAM_NOTAGS)); + $temp->add(new admin_setting_configtext('denyemailaddresses', get_string('denyemailaddresses', 'admin'), get_string('configdenyemailaddresses', 'admin'), '', PARAM_NOTAGS)); + $temp->add(new admin_setting_configcheckbox('verifychangedemail', get_string('verifychangedemail', 'admin'), get_string('configverifychangedemail', 'admin'), 1)); + + $temp->add(new admin_setting_configtext('recaptchapublickey', get_string('recaptchapublickey', 'admin'), get_string('configrecaptchapublickey', 'admin'), '', PARAM_NOTAGS)); + $temp->add(new admin_setting_configtext('recaptchaprivatekey', get_string('recaptchaprivatekey', 'admin'), get_string('configrecaptchaprivatekey', 'admin'), '', PARAM_NOTAGS)); + $ADMIN->add('authsettings', $temp); + + + if ($auths = get_plugin_list('auth')) { + $authsenabled = get_enabled_auth_plugins(); + $authbyname = array(); + + foreach ($auths as $auth => $authdir) { + $strauthname = get_string('pluginname', "auth_{$auth}"); + $authbyname[$strauthname] = $auth; + } + ksort($authbyname); + + foreach ($authbyname as $strauthname=>$authname) { + if (file_exists($authdir.'/settings.php')) { + // do not show disabled auths in tree, keep only settings link on manage page + $settings = new admin_settingpage('authsetting'.$authname, $strauthname, 'moodle/site:config', !in_array($authname, $authsenabled)); + if ($ADMIN->fulltree) { + include($authdir.'/settings.php'); + } + // TODO: finish implementation of common settings - locking, etc. + $ADMIN->add('authsettings', $settings); + + } else { + $ADMIN->add('authsettings', new admin_externalpage('authsetting'.$authname, $strauthname, "$CFG->wwwroot/$CFG->admin/auth_config.php?auth=$authname", 'moodle/site:config', !in_array($authname, $authsenabled))); + } + } + } + + + // Enrolment plugins + $ADMIN->add('modules', new admin_category('enrolments', get_string('enrolments', 'enrol'))); + $temp = new admin_settingpage('manageenrols', get_string('manageenrols', 'enrol')); + $temp->add(new admin_setting_manageenrols()); + if (empty($CFG->enrol_plugins_enabled)) { + $enabled = array(); + } else { + $enabled = explode(',', $CFG->enrol_plugins_enabled); + } + $enrols = get_plugin_list('enrol'); + $ADMIN->add('enrolments', $temp); + foreach($enrols as $enrol=>$enrolpath) { + if (!file_exists("$enrolpath/settings.php")) { + continue; + } + + $settings = new admin_settingpage('enrolsettings'.$enrol, get_string('pluginname', 'enrol_'.$enrol), 'moodle/site:config', !in_array($enrol, $enabled)); + // settings.php may create a subcategory or unset the settings completely + include("$enrolpath/settings.php"); + if ($settings) { + $ADMIN->add('enrolments', $settings); + } + + } + unset($enabled); + unset($enrols); + /// Editor plugins $ADMIN->add('modules', new admin_category('editorsettings', get_string('editors', 'editor'))); @@ -63,7 +141,7 @@ if ($hassiteconfig) { if (file_exists($CFG->dirroot . '/lib/editor/'.$editor.'/settings.php')) { $editor_setting = new admin_externalpage('editorsettings'.$editor, $editorstr, $url.'&action=edit&editor='.$editor); $ADMIN->add('editorsettings', $editor_setting); - } + } } /// License types $ADMIN->add('modules', new admin_category('licensesettings', get_string('license'))); @@ -284,7 +362,7 @@ if ($hassiteconfig) { $temp->add(new admin_setting_heading('webservicesaredisabled', '', get_string('disabledwarning', 'webservice'))); } $ADMIN->add('webservicesettings', $temp); - + if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext)) { // Question type settings. diff --git a/admin/settings/security.php b/admin/settings/security.php index ca4102c4e1f..4d0d6aae2e1 100644 --- a/admin/settings/security.php +++ b/admin/settings/security.php @@ -67,6 +67,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page $temp->add(new admin_setting_configtext('minpasswordupper', get_string('minpasswordupper', 'admin'), get_string('configminpasswordupper', 'admin'), 1, PARAM_INT)); $temp->add(new admin_setting_configtext('minpasswordnonalphanum', get_string('minpasswordnonalphanum', 'admin'), get_string('configminpasswordnonalphanum', 'admin'), 1, PARAM_INT)); $temp->add(new admin_setting_configtext('maxconsecutiveidentchars', get_string('maxconsecutiveidentchars', 'admin'), get_string('configmaxconsecutiveidentchars', 'admin'), 0, PARAM_INT)); + $temp->add(new admin_setting_configcheckbox('groupenrolmentkeypolicy', get_string('groupenrolmentkeypolicy', 'admin'), get_string('groupenrolmentkeypolicy_desc', 'admin'), 1)); $temp->add(new admin_setting_configcheckbox('disableuserimages', get_string('disableuserimages', 'admin'), get_string('configdisableuserimages', 'admin'), 0)); $temp->add(new admin_setting_configcheckbox('emailchangeconfirmation', get_string('emailchangeconfirmation', 'admin'), get_string('configemailchangeconfirmation', 'admin'), 1)); $ADMIN->add('security', $temp); diff --git a/admin/settings/users.php b/admin/settings/users.php index 36a1ecba2c7..cade4eee3a8 100644 --- a/admin/settings/users.php +++ b/admin/settings/users.php @@ -2,7 +2,6 @@ // This file defines settingpages and externalpages under the "users" category -$ADMIN->add('users', new admin_category('authsettings', get_string('authentication','admin'))); $ADMIN->add('users', new admin_category('accounts', get_string('accounts', 'admin'))); $ADMIN->add('users', new admin_category('roles', get_string('permissions', 'role'))); @@ -17,54 +16,6 @@ if ($hassiteconfig or has_capability('moodle/cohort:view', $systemcontext)) { // speedup for non-admins, add all caps used on this page - $temp = new admin_settingpage('manageauths', get_string('authsettings', 'admin')); - $temp->add(new admin_setting_manageauths()); - $temp->add(new admin_setting_heading('manageauthscommonheading', get_string('commonsettings', 'admin'), '')); - $temp->add(new admin_setting_special_registerauth()); - $temp->add(new admin_setting_configselect('guestloginbutton', get_string('guestloginbutton', 'auth'), - get_string('showguestlogin', 'auth'), '1', array('0'=>get_string('hide'), '1'=>get_string('show')))); - $temp->add(new admin_setting_configtext('alternateloginurl', get_string('alternateloginurl', 'auth'), - get_string('alternatelogin', 'auth', htmlspecialchars(get_login_url())), '')); - $temp->add(new admin_setting_configtext('forgottenpasswordurl', get_string('forgottenpasswordurl', 'auth'), - get_string('forgottenpassword', 'auth'), '')); - $temp->add(new admin_setting_confightmleditor('auth_instructions', get_string('instructions', 'auth'), - get_string('authinstructions', 'auth'), '')); - $temp->add(new admin_setting_configtext('allowemailaddresses', get_string('allowemailaddresses', 'admin'), get_string('configallowemailaddresses', 'admin'), '', PARAM_NOTAGS)); - $temp->add(new admin_setting_configtext('denyemailaddresses', get_string('denyemailaddresses', 'admin'), get_string('configdenyemailaddresses', 'admin'), '', PARAM_NOTAGS)); - $temp->add(new admin_setting_configcheckbox('verifychangedemail', get_string('verifychangedemail', 'admin'), get_string('configverifychangedemail', 'admin'), 1)); - - $temp->add(new admin_setting_configtext('recaptchapublickey', get_string('recaptchapublickey', 'admin'), get_string('configrecaptchapublickey', 'admin'), '', PARAM_NOTAGS)); - $temp->add(new admin_setting_configtext('recaptchaprivatekey', get_string('recaptchaprivatekey', 'admin'), get_string('configrecaptchaprivatekey', 'admin'), '', PARAM_NOTAGS)); - $ADMIN->add('authsettings', $temp); - - - if ($auths = get_plugin_list('auth')) { - $authsenabled = get_enabled_auth_plugins(); - $authbyname = array(); - - foreach ($auths as $auth => $authdir) { - $strauthname = get_string('pluginname', "auth_{$auth}"); - $authbyname[$strauthname] = $auth; - } - ksort($authbyname); - - foreach ($authbyname as $strauthname=>$authname) { - if (file_exists($authdir.'/settings.php')) { - // do not show disabled auths in tree, keep only settings link on manage page - $settings = new admin_settingpage('authsetting'.$authname, $strauthname, 'moodle/site:config', !in_array($authname, $authsenabled)); - if ($ADMIN->fulltree) { - include($authdir.'/settings.php'); - } - // TODO: finish implementation of common settings - locking, etc. - $ADMIN->add('authsettings', $settings); - - } else { - $ADMIN->add('authsettings', new admin_externalpage('authsetting'.$authname, $strauthname, "$CFG->wwwroot/$CFG->admin/auth_config.php?auth=$authname", 'moodle/site:config', !in_array($authname, $authsenabled))); - } - } - } - - if (empty($CFG->loginhttps)) { $securewwwroot = $CFG->wwwroot; } else { @@ -94,7 +45,7 @@ if ($hassiteconfig $studentroles = array(); $teacherroles = array(); $creatornewroles = array(); - + foreach (get_all_roles() as $role) { $rolename = strip_tags(format_string($role->name)) . ' ('. $role->shortname . ')'; $allroles[$role->id] = $rolename; @@ -135,7 +86,7 @@ if ($hassiteconfig $defaultstudentid = key($studentroles); reset($teacherroles); $defaultteacherid = key($teacherroles); - + if ($userroles) { reset($userroles); $defaultuserid = key($userroles); @@ -155,19 +106,12 @@ if ($hassiteconfig $temp->add(new admin_setting_configcheckbox('nodefaultuserrolelists', get_string('nodefaultuserrolelists', 'admin'), get_string('confignodefaultuserrolelists', 'admin'), 0)); if (!during_initial_install()) { - $temp->add(new admin_setting_configselect('defaultcourseroleid', get_string('defaultcourseroleid', 'admin'), - get_string('configdefaultcourseroleid', 'admin'), $defaultstudentid, $allroles)); $temp->add(new admin_setting_configselect('creatornewroleid', get_string('creatornewroleid', 'admin'), get_string('configcreatornewroleid', 'admin'), $defaultteacherid, $creatornewroles)); } $temp->add(new admin_setting_configcheckbox('autologinguests', get_string('autologinguests', 'admin'), get_string('configautologinguests', 'admin'), 0)); - if (!during_initial_install()) { - $temp->add(new admin_setting_configmultiselect('nonmetacoursesyncroleids', get_string('nonmetacoursesyncroleids', 'admin'), - get_string('confignonmetacoursesyncroleids', 'admin'), array(), $allroles)); - } - $temp->add(new admin_setting_configmultiselect('hiddenuserfields', get_string('hiddenuserfields', 'admin'), get_string('confighiddenuserfields', 'admin'), array(), array('description' => get_string('description'), diff --git a/admin/uploaduser.php b/admin/uploaduser.php index c58c998b061..bc2d1d55d7b 100755 --- a/admin/uploaduser.php +++ b/admin/uploaduser.php @@ -162,26 +162,21 @@ if ($formdata = $mform->is_cancelled()) { $weakpasswords = 0; // caches - $ccache = array(); // course cache - do not fetch all courses here, we will not probably use them all anyway! - $rolecache = array(); // roles lookup cache + $ccache = array(); // course cache - do not fetch all courses here, we will not probably use them all anyway! + $rolecache = uu_allowed_roles_cache(); // roles lookup cache + $manualcacche = array(); // cache of used manual enrol plugins in each course $allowedauths = uu_allowed_auths(); $allowedauths = array_keys($allowedauths); $availableauths = get_plugin_list('auth'); $availableauths = array_keys($availableauths); - $allowedroles = uu_allowed_roles(true); - foreach ($allowedroles as $rid=>$rname) { - $rolecache[$rid] = new object(); - $rolecache[$rid]->id = $rid; - $rolecache[$rid]->name = $rname; - if (!is_numeric($rname)) { // only non-numeric shornames are supported!!! - $rolecache[$rname] = new object(); - $rolecache[$rname]->id = $rid; - $rolecache[$rname]->name = $rname; - } + // we use only manual enrol plugin here, if it is disabled no enrol is done + if (enrol_is_enabled('manual')) { + $manual = enrol_get_plugin('manual'); + } else { + $manual = NULL; } - unset($allowedroles); // clear bulk selection if ($bulk) { @@ -210,7 +205,7 @@ if ($formdata = $mform->is_cancelled()) { // add fields to user object foreach ($line as $key => $value) { if ($value !== '') { - $key = $columns[$key]; + $key = $columns[$key]; // password is special field if ($key == 'password') { if ($value !== '') { @@ -365,16 +360,11 @@ if ($formdata = $mform->is_cancelled()) { $renameerrors++; continue; } - if ($DB->set_field('user', 'username', $user->username, array('id'=>$olduser->id))) { - $upt->track('username', '', 'normal', false); // clear previous - $upt->track('username', $oldusername.'-->'.$user->username, 'info'); - $upt->track('status', $struserrenamed); - $renames++; - } else { - $upt->track('status', $strusernotrenamedexists, 'error'); - $renameerrors++; - continue; - } + $DB->set_field('user', 'username', $user->username, array('id'=>$olduser->id)); + $upt->track('username', '', 'normal', false); // clear previous + $upt->track('username', $oldusername.'-->'.$user->username, 'info'); + $upt->track('status', $struserrenamed); + $renames++; } else { $upt->track('status', $strusernotrenamedmissing, 'error'); $renameerrors++; @@ -501,14 +491,9 @@ if ($formdata = $mform->is_cancelled()) { $upt->track('auth', $struserauthunsupported, 'warning'); } - if ($DB->update_record('user', $existinguser)) { - $upt->track('status', $struserupdated); - $usersupdated++; - } else { - $upt->track('status', $strusernotupdated, 'error'); - $userserrors++; - continue; - } + $DB->update_record('user', $existinguser); + $upt->track('status', $struserupdated); + $usersupdated++; // save custom profile fields data from csv file profile_save_data($existinguser); } @@ -555,26 +540,21 @@ if ($formdata = $mform->is_cancelled()) { } } - if ($user->id = $DB->insert_record('user', $user)) { - $info = ': ' . $user->username .' (ID = ' . $user->id . ')'; - $upt->track('status', $struseradded); - $upt->track('id', $user->id, 'normal', false); - $usersnew++; - if ($createpasswords and empty($user->password)) { - // passwords will be created and sent out on cron - set_user_preference('create_password', 1, $user->id); - set_user_preference('auth_forcepasswordchange', 1, $user->id); - $upt->track('password', get_string('new')); - } - if ($forcechangepassword) { - set_user_preference('auth_forcepasswordchange', 1, $user->id); - } - } else { - // Record not added -- possibly some other error - $upt->track('status', $strusernotaddederror, 'error'); - $userserrors++; - continue; + $user->id = $DB->insert_record('user', $user); + $info = ': ' . $user->username .' (ID = ' . $user->id . ')'; + $upt->track('status', $struseradded); + $upt->track('id', $user->id, 'normal', false); + $usersnew++; + if ($createpasswords and empty($user->password)) { + // passwords will be created and sent out on cron + set_user_preference('create_password', 1, $user->id); + set_user_preference('auth_forcepasswordchange', 1, $user->id); + $upt->track('password', get_string('new')); } + if ($forcechangepassword) { + set_user_preference('auth_forcepasswordchange', 1, $user->id); + } + // save custom profile fields data profile_save_data($user); @@ -595,9 +575,12 @@ if ($formdata = $mform->is_cancelled()) { } $i = substr($column, 6); + if (empty($user->{'course'.$i})) { + continue; + } $shortname = $user->{'course'.$i}; if (!array_key_exists($shortname, $ccache)) { - if (!$course = $DB->get_record('course', array('shortname'=>$shortname), 'id, shortname, defaultrole')) { + if (!$course = $DB->get_record('course', array('shortname'=>$shortname), 'id, shortname')) { $upt->track('enrolments', get_string('unknowncourse', 'error', $shortname), 'error'); continue; } @@ -606,62 +589,61 @@ if ($formdata = $mform->is_cancelled()) { } $courseid = $ccache[$shortname]->id; $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid); - - // find role - $rid = false; - if (!empty($user->{'role'.$i})) { - $addrole = $user->{'role'.$i}; - if (array_key_exists($addrole, $rolecache)) { - $rid = $rolecache[$addrole]->id; + if (!isset($manualcache[$courseid])) { + if ($instances = enrol_get_instances($courseid, false)) { + $manualcache[$courseid] = reset($instances); } else { - $upt->track('enrolments', get_string('unknownrole', 'error', $addrole), 'error'); - continue; + $manualcache[$courseid] = false; } + } - } else if (!empty($user->{'type'.$i})) { - // if no role, then find "old" enrolment type - $addtype = $user->{'type'.$i}; - if ($addtype < 1 or $addtype > 3) { - $upt->track('enrolments', $strerror.': typeN = 1|2|3', 'error'); - continue; - } else if ($addtype == 1 and empty($formdata->uulegacy1)) { - if (empty($ccache[$shortname]->defaultrole)) { - $rid = $CFG->defaultcourseroleid; + if ($manual and $manualcache[$courseid]) { + + // find role + $rid = false; + if (!empty($user->{'role'.$i})) { + $addrole = $user->{'role'.$i}; + if (array_key_exists($addrole, $rolecache)) { + $rid = $rolecache[$addrole]->id; } else { - $rid = $ccache[$shortname]->defaultrole; + $upt->track('enrolments', get_string('unknownrole', 'error', $addrole), 'error'); + continue; + } + + } else if (!empty($user->{'type'.$i})) { + // if no role, then find "old" enrolment type + $addtype = $user->{'type'.$i}; + if ($addtype < 1 or $addtype > 3) { + $upt->track('enrolments', $strerror.': typeN = 1|2|3', 'error'); + continue; + } else if (empty($formdata->{'uulegacy'.$addtype})) { + continue; + } else { + $rid = $formdata->{'uulegacy'.$addtype}; } } else { - $rid = $formdata->{'uulegacy'.$addtype}; + // no role specified, use the default from manual enrol plugin + $rid = $manualcache[$courseid]->roleid; } - } else { - // no role specified, use the default - if (empty($ccache[$shortname]->defaultrole)) { - $rid = $CFG->defaultcourseroleid; - } else { - $rid = $ccache[$shortname]->defaultrole; - } - } + if ($rid) { + // find duration + $timestart = 0; + $timeend = 0; + if (!empty($user->{'enrolperiod'.$i})) { + $duration = (int)$user->{'enrolperiod'.$i} * 86400; // convert days to seconds + if ($duration > 0) { // sanity check + $timestart = time(); + $timeend = $timestart + $duration; + } + } - // find duration - $timestart = 0; - $timeend = 0; - if (!empty($user->{'enrolperiod'.$i})) { - $duration = (int)$user->{'enrolperiod'.$i} * 86400; // convert days to seconds - if ($duration > 0) { // sanity check - $timestart = time(); - $timeend = $timestart + $duration; - } - } + $manual->enrol_user($manualcache[$courseid], $user->id, $rid, $timestart, $timeend, true); - if ($rid) { - $a = new object(); - $a->course = $shortname; - $a->role = $rolecache[$rid]->name; - if (role_assign($rid, $user->id, 0, $coursecontext->id, $timestart, $timeend)) { - $upt->track('enrolments', get_string('enrolledincourserole', '', $a)); - } else { - $upt->track('enrolments', get_string('enrolledincoursenotrole', '', $a), 'error'); + $a = new object(); + $a->course = $shortname; + $a->role = $rolecache[$rid]->name; + $upt->track('enrolments', get_string('enrolledincourserole', 'enrol_manual', $a)); } } @@ -708,6 +690,8 @@ if ($formdata = $mform->is_cancelled()) { try { if (groups_add_member($gid, $user->id)) { $upt->track('enrolments', get_string('addedtogroup', '', $gname)); + } else { + $upt->track('enrolments', get_string('addedtogroupnot', '', $gname), 'error'); } } catch (moodle_exception $e) { $upt->track('enrolments', get_string('addedtogroupnot', '', $gname), 'error'); @@ -971,7 +955,7 @@ class uu_progress_tracker { echo ''.get_string('email').''; echo ''.get_string('password').''; echo ''.get_string('authentication').''; - echo ''.get_string('enrolments').''; + echo ''.get_string('enrolments', 'enrol').''; echo ''.get_string('delete').''; echo ''; $this->_row = null; @@ -1149,7 +1133,7 @@ function uu_allowed_auths() { global $CFG; // only following plugins are guaranteed to work properly - // TODO: add support for more plguins in 2.0 + // TODO: add support for more plugins in 2.0 $whitelist = array('manual', 'nologin', 'none', 'email'); $plugins = get_enabled_auth_plugins(); $choices = array(); @@ -1161,21 +1145,25 @@ function uu_allowed_auths() { } /** - * Returns list of non administrator roles + * Returns list of roles that are assignable in courses */ -function uu_allowed_roles($shortname=false) { - global $CFG; - - $roles = get_all_roles(); - $choices = array(); - foreach($roles as $role) { - if ($shortname) { - $choices[$role->id] = $role->shortname; - } else { - $choices[$role->id] = format_string($role->name); - } - } - - return $choices; +function uu_allowed_roles() { + // let's cheat a bit, frontpage is guaranteed to exist and has the same list of roles ;-) + $roles = get_assignable_roles(get_context_instance(CONTEXT_COURSE, SITEID), ROLENAME_ORIGINALANDSHORT); + return array_reverse($roles, true); } +function uu_allowed_roles_cache() { + $allowedroles = get_assignable_roles(get_context_instance(CONTEXT_COURSE, SITEID), ROLENAME_SHORT); + foreach ($allowedroles as $rid=>$rname) { + $rolecache[$rid] = new object(); + $rolecache[$rid]->id = $rid; + $rolecache[$rid]->name = $rname; + if (!is_numeric($rname)) { // only non-numeric shortnames are supported!!! + $rolecache[$rname] = new object(); + $rolecache[$rname]->id = $rid; + $rolecache[$rname]->name = $rname; + } + } + return $rolecache; +} diff --git a/admin/uploaduser_form.php b/admin/uploaduser_form.php index 88a1ced61a6..29d3cb3d9f8 100644 --- a/admin/uploaduser_form.php +++ b/admin/uploaduser_form.php @@ -59,7 +59,7 @@ class admin_uploaduser_form2 extends moodleform { // I am the template user, why should it be the administrator? we have roles now, other ppl may use this script ;-) $templateuser = $USER; -// upload settings and file + // upload settings and file $mform->addElement('header', 'settingsheader', get_string('settings')); $mform->addElement('static', 'uutypelabel', get_string('uuoptype', 'admin') ); @@ -105,7 +105,7 @@ class admin_uploaduser_form2 extends moodleform { $mform->addElement('select', 'uubulk', get_string('uubulk', 'admin'), $choices); $mform->setDefault('uubulk', 0); -// roles selection + // roles selection $showroles = false; foreach ($columns as $column) { if (preg_match('/^type\d+$/', $column)) { @@ -118,31 +118,41 @@ class admin_uploaduser_form2 extends moodleform { $choices = uu_allowed_roles(true); - $choices[0] = get_string('uucoursedefaultrole', 'admin'); $mform->addElement('select', 'uulegacy1', get_string('uulegacy1role', 'admin'), $choices); - $mform->setDefault('uulegacy1', 0); - unset($choices[0]); + if ($studentroles = get_archetype_roles('student')) { + foreach ($studentroles as $role) { + if (isset($choices[$role->id])) { + $mform->setDefault('uulegacy1', $role->id); + break; + } + } + unset($studentroles); + } $mform->addElement('select', 'uulegacy2', get_string('uulegacy2role', 'admin'), $choices); if ($editteacherroles = get_archetype_roles('editingteacher')) { - $editteacherrole = array_shift($editteacherroles); /// Take the first one - $mform->setDefault('uulegacy2', $editteacherrole->id); + foreach ($editteacherroles as $role) { + if (isset($choices[$role->id])) { + $mform->setDefault('uulegacy2', $role->id); + break; + } + } unset($editteacherroles); - } else { - $mform->setDefault('uulegacy2', $CFG->defaultcourseroleid); } $mform->addElement('select', 'uulegacy3', get_string('uulegacy3role', 'admin'), $choices); if ($teacherroles = get_archetype_roles('teacher')) { - $teacherrole = array_shift($teacherroles); /// Take the first one - $mform->setDefault('uulegacy3', $teacherrole->id); + foreach ($teacherroles as $role) { + if (isset($choices[$role->id])) { + $mform->setDefault('uulegacy3', $role->id); + break; + } + } unset($teacherroles); - } else { - $mform->setDefault('uulegacy3', $CFG->defaultcourseroleid); } } -// default values + // default values $mform->addElement('header', 'defaultheader', get_string('defaultvalues', 'admin')); $mform->addElement('text', 'username', get_string('username'), 'size="20"'); @@ -248,10 +258,10 @@ class admin_uploaduser_form2 extends moodleform { $mform->setType('address', PARAM_MULTILANG); $mform->setAdvanced('address'); - /// Next the profile defaults + // Next the profile defaults profile_definition($mform); -// hidden fields + // hidden fields $mform->addElement('hidden', 'iid'); $mform->setType('iid', PARAM_INT); @@ -363,7 +373,7 @@ class admin_uploaduser_form2 extends moodleform { class admin_uploaduser_form3 extends moodleform { function definition (){ global $CFG, $USER; - $mform =& $this->_form; + $mform =& $this->_form; $this->add_action_buttons(false, get_string('uploadnewfile')); } } diff --git a/admin/user/user_bulk_enrol.php b/admin/user/user_bulk_enrol.php index 4b99ef87e9a..4660a3ee430 100644 --- a/admin/user/user_bulk_enrol.php +++ b/admin/user/user_bulk_enrol.php @@ -84,17 +84,13 @@ if(!empty($processed)) { $ids = explode(',', $info); if(!empty($ids[2])) { $context = get_context_instance(CONTEXT_COURSE, $ids[1]); - if( role_assign(5, $ids[0], 0, $context->id) ) { - continue; - } + role_assign(5, $ids[0], $context->id); } else { if( empty($ids[1] ) ) { continue; } $context = get_context_instance(CONTEXT_COURSE, $ids[1]); - if( role_unassign(5, $ids[0], 0, $context->id) ) { - continue; - } + role_unassign(5, $ids[0], $context->id); } } redirect($return, get_string('changessaved')); @@ -104,14 +100,12 @@ if(!empty($processed)) { echo '
'; echo ''; $count = 0; -foreach($users as $user) -{ +foreach($users as $user) { $temparray = array ( ''.$user->fullname.'' ); - $mycourses = get_my_courses($user->id); - foreach($courses as $acourse) - { + $mycourses = enrol_get_users_courses($user->id, false); + foreach($courses as $acourse) { $state = ''; if (isset($mycourses[$acourse->id])) { $state = 'checked="checked"'; diff --git a/admin/webservice/testclient_forms.php b/admin/webservice/testclient_forms.php index 5f5f3780f1a..342fc353b61 100644 --- a/admin/webservice/testclient_forms.php +++ b/admin/webservice/testclient_forms.php @@ -25,129 +25,6 @@ class webservice_test_client_form extends moodleform { // === Test client forms === - -class moodle_enrol_role_assign_form extends moodleform { - public function definition() { - global $CFG; - - $mform = $this->_form; - - - $mform->addElement('header', 'wstestclienthdr', get_string('testclient', 'webservice')); - - //note: these values are intentionally PARAM_RAW - we want users to test any rubbish as parameters - $data = $this->_customdata; - if ($data['authmethod'] == 'simple') { - $mform->addElement('text', 'wsusername', 'wsusername'); - $mform->addElement('text', 'wspassword', 'wspassword'); - } else if ($data['authmethod'] == 'token') { - $mform->addElement('text', 'token', 'token'); - } - - $mform->addElement('hidden', 'authmethod', $data['authmethod']); - $mform->setType('authmethod', PARAM_SAFEDIR); - - /// specific to the create users function - $mform->addElement('text', 'userid', 'userid'); - $mform->addElement('text', 'roleid', 'roleid'); - $mform->addElement('text', 'contextid', 'contextid'); - $mform->addElement('text', 'timestart', 'timestart'); - $mform->addElement('text', 'timeend', 'timeend'); - - $mform->addElement('hidden', 'function'); - $mform->setType('function', PARAM_SAFEDIR); - - $mform->addElement('hidden', 'protocol'); - $mform->setType('protocol', PARAM_SAFEDIR); - - - - $mform->addElement('static', 'warning', '', get_string('executewarnign', 'webservice')); - - $this->add_action_buttons(true, get_string('execute', 'webservice')); - } - - public function get_params() { - if (!$data = $this->get_data()) { - return null; - } - // remove unused from form data - unset($data->submitbutton); - unset($data->protocol); - unset($data->function); - unset($data->wsusername); - unset($data->wspassword); - unset($data->token); - unset($data->authmethod); - - $params = array(); - $params['enrolments'] = array(); - $params['enrolments'][] = (array)$data; - - return $params; - } -} - -class moodle_enrol_role_unassign_form extends moodleform { - public function definition() { - global $CFG; - - $mform = $this->_form; - - - $mform->addElement('header', 'wstestclienthdr', get_string('testclient', 'webservice')); - - //note: these values are intentionally PARAM_RAW - we want users to test any rubbish as parameters - $data = $this->_customdata; - if ($data['authmethod'] == 'simple') { - $mform->addElement('text', 'wsusername', 'wsusername'); - $mform->addElement('text', 'wspassword', 'wspassword'); - } else if ($data['authmethod'] == 'token') { - $mform->addElement('text', 'token', 'token'); - } - - $mform->addElement('hidden', 'authmethod', $data['authmethod']); - $mform->setType('authmethod', PARAM_SAFEDIR); - - /// specific to the create users function - $mform->addElement('text', 'userid', 'userid'); - $mform->addElement('text', 'roleid', 'roleid'); - $mform->addElement('text', 'contextid', 'contextid'); - - $mform->addElement('hidden', 'function'); - $mform->setType('function', PARAM_SAFEDIR); - - $mform->addElement('hidden', 'protocol'); - $mform->setType('protocol', PARAM_SAFEDIR); - - - - $mform->addElement('static', 'warning', '', get_string('executewarnign', 'webservice')); - - $this->add_action_buttons(true, get_string('execute', 'webservice')); - } - - public function get_params() { - if (!$data = $this->get_data()) { - return null; - } - // remove unused from form data - unset($data->submitbutton); - unset($data->protocol); - unset($data->function); - unset($data->wsusername); - unset($data->wspassword); - unset($data->token); - unset($data->authmethod); - - $params = array(); - $params['unenrolments'] = array(); - $params['unenrolments'][] = (array)$data; - - return $params; - } -} - class moodle_user_create_users_form extends moodleform { public function definition() { global $CFG; @@ -273,7 +150,7 @@ class moodle_user_update_users_form extends moodleform { if (!$data = $this->get_data()) { return null; } - + //set customfields if (!empty($data->customfieldtype)) { $data->customfields = array(array('type' => $data->customfieldtype, 'value' => $data->customfieldvalue)); @@ -369,7 +246,7 @@ class moodle_user_delete_users_form extends moodleform { $params['userids'][] = $data->userids[$i]; } /// end of specific code to the create users function - + return $params; } } @@ -449,7 +326,7 @@ class moodle_group_create_groups_form extends moodleform { global $CFG; $mform = $this->_form; - + $mform->addElement('header', 'wstestclienthdr', get_string('testclient', 'webservice')); @@ -476,7 +353,7 @@ class moodle_group_create_groups_form extends moodleform { $mform->addElement('hidden', 'protocol'); $mform->setType('protocol', PARAM_SAFEDIR); - + $mform->addElement('static', 'warning', '', get_string('executewarnign', 'webservice')); diff --git a/auth/cas/auth.php b/auth/cas/auth.php index f2a498fedfb..c2aaa3cb68b 100644 --- a/auth/cas/auth.php +++ b/auth/cas/auth.php @@ -824,9 +824,9 @@ if ( !is_object($PHPCAS_CLIENT) ) { // update course creators if needed if ($creatorrole !== false) { if ($this->iscreator($user->username)) { - role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'cas'); + role_assign($creatorrole->id, $user->id, $sitecontext->id, 'auth_cas'); } else { - role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id, 'cas'); + role_unassign($creatorrole->id, $user->id, $sitecontext->id, 'auth_cas'); } } } @@ -883,7 +883,7 @@ if ( !is_object($PHPCAS_CLIENT) ) { // add course creators if needed if ($creatorrole !== false and $this->iscreator($user->username)) { - role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'cas'); + role_assign($creatorrole->id, $user->id, $sitecontext->id, 'auth_cas'); } } $transaction->allow_commit(); @@ -1127,10 +1127,10 @@ if (!empty($this->config->attrcreators)) { $creatorrole = array_shift($roles); // We can only use one, let's use the first one $systemcontext = get_context_instance(CONTEXT_SYSTEM); if ($iscreator) { // Following calls will not create duplicates - role_assign($creatorrole->id, $user->id, 0, $systemcontext->id, 0, 0, 0, 'cas'); + role_assign($creatorrole->id, $user->id, $systemcontext->id, 'auth_cas'); } else { //unassign only if previously assigned by this plugin! - role_unassign($creatorrole->id, $user->id, 0, $systemcontext->id, 'cas'); + role_unassign($creatorrole->id, $user->id, $systemcontext->id, 'auth_cas'); } } } diff --git a/auth/fc/auth.php b/auth/fc/auth.php index ce9a5933399..3717dc4bf7f 100644 --- a/auth/fc/auth.php +++ b/auth/fc/auth.php @@ -183,10 +183,10 @@ class auth_plugin_fc extends auth_plugin_base { $systemcontext = get_context_instance(CONTEXT_SYSTEM); if ($iscreator) { // Following calls will not create duplicates - role_assign($creatorrole->id, $user->id, 0, $systemcontext->id, 0, 0, 0, 'fc'); + role_assign($creatorrole->id, $user->id, $systemcontext->id, 'auth_fc'); } else { //unassign only if previously assigned by this plugin! - role_unassign($creatorrole->id, $user->id, 0, $systemcontext->id, 'fc'); + role_unassign($creatorrole->id, $user->id, $systemcontext->id, 'auth_fc'); } } } diff --git a/auth/ldap/auth.php b/auth/ldap/auth.php index 0bac19c5fb0..f8008cf64b7 100644 --- a/auth/ldap/auth.php +++ b/auth/ldap/auth.php @@ -744,9 +744,9 @@ class auth_plugin_ldap extends auth_plugin_base { // update course creators if needed if ($creatorrole !== false) { if ($this->iscreator($user->username)) { - role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap'); + role_assign($creatorrole->id, $user->id, $sitecontext->id, 'auth_ldap'); } else { - role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id, 'ldap'); + role_unassign($creatorrole->id, $user->id, $sitecontext->id, 'auth_ldap'); } } } @@ -807,7 +807,7 @@ class auth_plugin_ldap extends auth_plugin_base { // add course creators if needed if ($creatorrole !== false and $this->iscreator($user->username)) { - role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap'); + role_assign($creatorrole->id, $user->id, $sitecontext->id, 'auth_ldap'); } } $transaction->allow_commit(); @@ -1948,10 +1948,10 @@ class auth_plugin_ldap extends auth_plugin_base { $systemcontext = get_context_instance(CONTEXT_SYSTEM); if ($iscreator) { // Following calls will not create duplicates - role_assign($creatorrole->id, $user->id, 0, $systemcontext->id, 0, 0, 0, 'ldap'); + role_assign($creatorrole->id, $user->id, $systemcontext->id, 'auth_ldap'); } else { //unassign only if previously assigned by this plugin! - role_unassign($creatorrole->id, $user->id, 0, $systemcontext->id, 'ldap'); + role_unassign($creatorrole->id, $user->id, $systemcontext->id, 'auth_ldap'); } } } diff --git a/auth/mnet/auth.php b/auth/mnet/auth.php index 55af2c550c6..2ee6098d079 100644 --- a/auth/mnet/auth.php +++ b/auth/mnet/auth.php @@ -87,7 +87,7 @@ class auth_plugin_mnet extends auth_plugin_base { } $userdata['myhosts'] = array(); - if($courses = get_my_courses($user->id, 'id', 'id, visible')) { + if ($courses = enrol_get_users_courses($user->id, false)) { $userdata['myhosts'][] = array('name'=> $SITE->shortname, 'url' => $CFG->wwwroot, 'count' => count($courses)); } @@ -349,41 +349,33 @@ class auth_plugin_mnet extends auth_plugin_base { // pass username and an assoc array of "my courses" // with info so that the IDP can maintain mnet_enrol_assignments $mnetrequest->add_param($remoteuser->username); - $fields = 'id, category, sortorder, fullname, shortname, idnumber, summary, - startdate, cost, currency, defaultrole, visible'; - $courses = get_my_courses($localuser->id, 'visible DESC,sortorder ASC', $fields); + $fields = 'id, category, sortorder, fullname, shortname, idnumber, summary, startdate, visible'; + $courses = enrol_get_users_courses($localuser->id, false, $fields, 'visible DESC,sortorder ASC'); if (is_array($courses) && !empty($courses)) { // Second request to do the JOINs that we'd have done - // inside get_my_courses() if we had been allowed + // inside enrol_get_users_courses() if we had been allowed $sql = "SELECT c.id, - cc.name AS cat_name, cc.description AS cat_description, - r.shortname as defaultrolename + cc.name AS cat_name, cc.description AS cat_description FROM {course} c JOIN {course_categories} cc ON c.category = cc.id - LEFT OUTER JOIN {role} r ON c.defaultrole = r.id WHERE c.id IN (" . join(',',array_keys($courses)) . ')'; $extra = $DB->get_records_sql($sql); $keys = array_keys($courses); - $defaultrolename = $DB->get_field('role', 'shortname', array('id'=>$CFG->defaultcourseroleid)); + $defaultrole = get_default_course_role($ccache[$shortname]); //TODO: rewrite this completely, there is no default course role any more!!! foreach ($keys AS $id) { if ($courses[$id]->visible == 0) { unset($courses[$id]); continue; } $courses[$id]->cat_id = $courses[$id]->category; - $courses[$id]->defaultroleid = $courses[$id]->defaultrole; + $courses[$id]->defaultroleid = $defaultrole->id; unset($courses[$id]->category); - unset($courses[$id]->defaultrole); unset($courses[$id]->visible); $courses[$id]->cat_name = $extra[$id]->cat_name; $courses[$id]->cat_description = $extra[$id]->cat_description; - if (!empty($extra[$id]->defaultrolename)) { - $courses[$id]->defaultrolename = $extra[$id]->defaultrolename; - } else { - $courses[$id]->defaultrolename = $defaultrolename; - } + $courses[$id]->defaultrolename = $defaultrole->name; // coerce to array $courses[$id] = (array)$courses[$id]; } @@ -486,10 +478,6 @@ class auth_plugin_mnet extends auth_plugin_base { c.idnumber, c.summary, c.startdate, - c.cost, - c.currency, - c.defaultroleid, - c.defaultrolename, a.id as assignmentid FROM {mnet_enrol_course} c diff --git a/auth/shibboleth/index.php b/auth/shibboleth/index.php index ddb57ffd2a2..ff8a385090f 100644 --- a/auth/shibboleth/index.php +++ b/auth/shibboleth/index.php @@ -76,7 +76,7 @@ } } - check_enrolment_plugins($USER); + enrol_check_plugins($USER); load_all_capabilities(); /// This is what lets the user do anything on the site :-) redirect($urltogo); diff --git a/backup/backuplib.php b/backup/backuplib.php index f438375f81b..0a4c3f5c4b9 100644 --- a/backup/backuplib.php +++ b/backup/backuplib.php @@ -162,10 +162,7 @@ function backup_get_enrolled_users ($courseid) { global $CFG; - // get all users with moodle/course:participate capability, this will include people - // assigned at cat level, or site level - // but it should be ok if they have no direct assignment at course, mod, block level - return get_users_by_capability(get_context_instance(CONTEXT_COURSE, $courseid), 'moodle/course:participate', '', '', '', '', '', '', false); + return get_enrolled_users(get_context_instance(CONTEXT_COURSE, $courseid)); } //Returns all users ids (every record in users table) diff --git a/backup/moodle2/backup_course_task.class.php b/backup/moodle2/backup_course_task.class.php index 09abf4d7f8e..34eedb71ef8 100644 --- a/backup/moodle2/backup_course_task.class.php +++ b/backup/moodle2/backup_course_task.class.php @@ -69,9 +69,11 @@ class backup_course_task extends backup_task { $this->add_step(new create_taskbasepath_directory('create_course_directory')); // Create the course.xml file with course & category information - // annotating some bits, metacourse info, tags and module restrictions + // annotating some bits, tags and module restrictions $this->add_step(new backup_course_structure_step('course_info', 'course.xml')); + //TODO: MDL-22793 - add user_enrolments entries + // Annotate the groups used in already annotated groupings $this->add_step(new backup_annotate_groups_from_groupings('annotate_groups')); diff --git a/backup/moodle2/backup_final_task.class.php b/backup/moodle2/backup_final_task.class.php index ef660e57c3b..d0461e31714 100644 --- a/backup/moodle2/backup_final_task.class.php +++ b/backup/moodle2/backup_final_task.class.php @@ -40,6 +40,8 @@ class backup_final_task extends backup_task { $coursectxid = get_context_instance(CONTEXT_COURSE, $this->get_courseid())->id; $this->add_setting(new backup_activity_generic_setting(backup::VAR_CONTEXTID, base_setting::IS_INTEGER, $coursectxid)); + //TODO: MDL-22793 add enrol instances of enabled enrol plugins in course, + // Generate the groups file with the final annotated groups and groupings // including membership based on setting $this->add_step(new backup_groups_structure_step('groups', 'groups.xml')); diff --git a/backup/moodle2/backup_stepslib.php b/backup/moodle2/backup_stepslib.php index f81388ab270..0ab76fc2803 100644 --- a/backup/moodle2/backup_stepslib.php +++ b/backup/moodle2/backup_stepslib.php @@ -202,7 +202,7 @@ class backup_section_structure_step extends backup_structure_step { /** * structure step that will generate the course.xml file for the course, including - * course category reference, tags, metacourse, modules restriction information + * course category reference, tags, modules restriction information * and some annotations (files & groupings) */ class backup_course_structure_step extends backup_structure_step { @@ -213,16 +213,15 @@ class backup_course_structure_step extends backup_structure_step { // Define each element separated $course = new backup_nested_element('course', array('id', 'contextid'), array( - 'shortname', 'fullname', 'idnumber', 'password', + 'shortname', 'fullname', 'idnumber', 'summary', 'summaryformat', 'format', 'showgrades', - 'newsitems', 'guest', 'startdate', 'enrolperiod', + 'newsitems', 'startdate', 'numsections', 'marker', 'maxbytes', 'showreports', 'visible', 'hiddensections', 'groupmode', 'groupmodeforce', - 'defaultgroupingid', 'lang', 'theme', 'cost', - 'currency', 'timecreated', 'timemodified', 'metacourse', - 'requested', 'restrictmodules', 'expirynotify', 'expirythreshold', - 'notifystudents', 'enrollable', 'enrolstartdate', 'enrolenddate', - 'enrol', 'defaultrole', 'enablecompletion')); + 'defaultgroupingid', 'lang', 'theme', + 'timecreated', 'timemodified', + 'requested', 'restrictmodules', + 'enablecompletion')); $category = new backup_nested_element('category', array('id'), array( 'name', 'description')); @@ -272,7 +271,6 @@ class backup_course_structure_step extends backup_structure_step { // Some annotations - $course->annotate_ids('role', 'defaultrole'); $course->annotate_ids('grouping', 'defaultgroupingid'); $course->annotate_files(array('course_summary', 'course_content'), null); @@ -307,8 +305,7 @@ class backup_roles_structure_step extends backup_structure_step { $assignments = new backup_nested_element('role_assignments'); $assignment = new backup_nested_element('assignment', array('id'), array( - 'roleid', 'userid', 'hidden', 'timestart', - 'timeend', 'timemodified', 'modifierid', 'enrol', + 'roleid', 'userid', 'timemodified', 'modifierid', 'component', //TODO: MDL-22793 add itemid here 'sortorder')); // Build the tree @@ -714,8 +711,7 @@ class backup_users_structure_step extends backup_structure_step { $assignments = new backup_nested_element('role_assignments'); $assignment = new backup_nested_element('assignment', array('id'), array( - 'roleid', 'userid', 'hidden', 'timestart', - 'timeend', 'timemodified', 'modifierid', 'enrol', + 'roleid', 'userid', 'timemodified', 'modifierid', 'component', //TODO: MDL-22793 add itemid here 'sortorder')); // Build the tree diff --git a/backup/restore_check.html b/backup/restore_check.html index 42639080c73..7ffff213f5d 100644 --- a/backup/restore_check.html +++ b/backup/restore_check.html @@ -92,8 +92,6 @@ } //restoreto $restore_restoreto = required_param('restore_restoreto', PARAM_INT); - //restore_metacourse - $restore_metacourse = required_param('restore_metacourse', PARAM_INT); //restore_users $restore_users = required_param('restore_users', PARAM_INT); @@ -140,7 +138,6 @@ } } $restore->restoreto=$restore_restoreto; - $restore->metacourse=$restore_metacourse; $restore->users=$restore_users; $restore->groups=$restore_groups; $restore->logs=$restore_logs; @@ -220,15 +217,9 @@ //Check site $site = get_site(); - // Non-cached - get accessinfo - if (isset($USER->access)) { - $accessinfo = $USER->access; - } else { - $accessinfo = get_user_access_sitewide($USER->id); - } - // Get all the courses the user is able to restore to - $mycourses = get_user_courses_bycap($USER->id, 'moodle/restore:restorecourse', $accessinfo, true, 'c.sortorder ASC', array('id', 'fullname', 'shortname', 'visible')); + //TODO: use better function which includes all courses for admins + $mycourses = get_user_courses_bycap($USER->id, 'moodle/restore:restorecourse'); // Calculate if the user can create courses $cancreatecourses = user_can_create_courses(); diff --git a/backup/restore_form.html b/backup/restore_form.html index 97f42a24d1b..9d8a5b76a69 100644 --- a/backup/restore_form.html +++ b/backup/restore_form.html @@ -77,11 +77,6 @@ } } - //Check other parameters - if (!isset($restore_metacourse)) { - $restore_metacourse = 1; - } - if (!isset($restore_users)) { $restore_users = 1; } @@ -201,14 +196,8 @@ function selectItemInCheckboxByName(formId, checkName, checked ) { // permission should have been checked already - // Non-cached - get accessinfo - if (isset($USER->access)) { - $accessinfo = $USER->access; - } else { - $accessinfo = get_user_access_sitewide($USER->id); - } - - $mycourses = get_user_courses_bycap($USER->id, 'moodle/restore:restorecourse', $accessinfo, true); + //TODO: use better function which includes all courses for admins + $mycourses = get_user_courses_bycap($USER->id, 'moodle/restore:restorecourse'); // if the user can restore to current course, grant the "current" options if (has_capability('moodle/restore:restorecourse', get_context_instance(CONTEXT_COURSE, $id))){ @@ -418,22 +407,6 @@ function selectItemInCheckboxByName(formId, checkName, checked ) { //Line echo "$nonrestmod
"; - //Now print the Metacourse tr - echo ""; - echo ""; - echo ''; - echo ""; - //If metacourse are in the backup file, show menu, else fixed to no - if ($info->backup_metacourse == "true") { - $metacourse_options = array(); - $metacourse_options[0] = get_string("no"); - $metacourse_options[1] = get_string("yes"); - echo html_writer::select($metacourse_options, "restore_metacourse", $restore_metacourse, false); - } else { - echo get_string("no"); - echo ""; - } - echo ""; //Now print the Users tr echo ""; echo ""; diff --git a/backup/restorelib.php b/backup/restorelib.php index 64d75d1406e..a6ac3ee045e 100644 --- a/backup/restorelib.php +++ b/backup/restorelib.php @@ -1555,9 +1555,7 @@ define('RESTORE_GROUPS_GROUPINGS', 3); if(!isset($restore->userswhocanviewcourse)) { // Because this is only used here, there is no point requesting // anything except id - $restore->userswhocanviewcourse=get_users_by_capability( - get_context_instance(CONTEXT_COURSE, $restore->course_id), - 'moodle/course:participate','u.id'); + $restore->userswhocanviewcourse = get_enrolled_users(get_context_instance(CONTEXT_COURSE, $restore->course_id), '', 0, 'u.id'); } foreach($info->completiondata as $data) { @@ -9703,13 +9701,7 @@ WHERE return true; } - // Non-cached - get accessinfo - if (isset($USER->access)) { - $accessinfo = $USER->access; - } else { - $accessinfo = get_user_access_sitewide($USER->id); - } - $courses = get_user_courses_bycap($USER->id, 'moodle/restore:rolldates', $accessinfo, true); + $courses = get_user_courses_bycap($USER->id, 'moodle/restore:rolldates'); return !empty($courses); } diff --git a/blocks/course_list/block_course_list.php b/blocks/course_list/block_course_list.php index 3a1923a9ae1..0d52ebd7db1 100644 --- a/blocks/course_list/block_course_list.php +++ b/blocks/course_list/block_course_list.php @@ -36,11 +36,8 @@ class block_course_list extends block_list { if (empty($CFG->disablemycourses) and isloggedin() and !isguestuser() and !(has_capability('moodle/course:update', get_context_instance(CONTEXT_SYSTEM)) and $adminseesall)) { // Just print My Courses - if ($courses = get_my_courses($USER->id, 'visible DESC, fullname ASC')) { + if ($courses = enrol_get_my_courses(NULL, 'visible DESC, fullname ASC')) { foreach ($courses as $course) { - if ($course->id == SITEID) { - continue; - } $linkcss = $course->visible ? "" : " class=\"dimmed\" "; $this->content->items[]="shortname) . "\" ". "href=\"$CFG->wwwroot/course/view.php?id=$course->id\">" . format_string($course->fullname) . ""; diff --git a/blocks/course_overview/block_course_overview.php b/blocks/course_overview/block_course_overview.php index 4c494178d1c..a67a60352b7 100644 --- a/blocks/course_overview/block_course_overview.php +++ b/blocks/course_overview/block_course_overview.php @@ -65,7 +65,7 @@ class block_course_overview extends block_base { $courses_limit = $courses_limit + 1; } - $courses = get_my_courses($USER->id, 'visible DESC,sortorder ASC', '*', false, $courses_limit); + $courses = enrol_get_my_courses(NULL, 'visible DESC,sortorder ASC', '*', $courses_limit); $site = get_site(); $course = $site; //just in case we need the old global $course hack diff --git a/blocks/course_summary/block_course_summary.php b/blocks/course_summary/block_course_summary.php index 6a86866576a..94d7431ca77 100644 --- a/blocks/course_summary/block_course_summary.php +++ b/blocks/course_summary/block_course_summary.php @@ -27,7 +27,7 @@ class block_course_summary extends block_base { $options = new object(); $options->noclean = true; // Don't clean Javascripts etc $context = get_context_instance(CONTEXT_COURSE, $this->page->course->id); - $this->page->course->summary = file_rewrite_pluginfile_urls($this->page->course->summary, 'pluginfile.php', $context->id, 'course_summary', $this->page->course->id); + $this->page->course->summary = file_rewrite_pluginfile_urls($this->page->course->summary, 'pluginfile.php', $context->id, 'course_summary', NULL); $this->content->text = format_text($this->page->course->summary, $this->page->course->summaryformat, $options); if ($this->page->user_is_editing()) { if($this->page->course->id == SITEID) { diff --git a/blocks/course_summary/db/upgrade.php b/blocks/course_summary/db/upgrade.php index 144d2335c19..d408e840066 100644 --- a/blocks/course_summary/db/upgrade.php +++ b/blocks/course_summary/db/upgrade.php @@ -9,7 +9,7 @@ // // The upgrade function in this file will attempt // to perform all the necessary actions to upgrade -// your older installtion to the current version. +// your older installation to the current version. // // If there's something it cannot do itself, it // will tell you what you need to do. diff --git a/calendar/export_execute.php b/calendar/export_execute.php index 757dc34a84b..1c676be3f69 100644 --- a/calendar/export_execute.php +++ b/calendar/export_execute.php @@ -33,7 +33,7 @@ $allowed_time = array('weeknow', 'weeknext', 'monthnow', 'monthnext', 'recentupc if(!empty($what) && !empty($time)) { if(in_array($what, $allowed_what) && in_array($time, $allowed_time)) { - $courses = get_my_courses($user->id, NULL, 'id, visible, shortname'); + $courses = enrol_get_users_courses($user->id, true, 'id, visible, shortname'); if ($what == 'all') { $users = $user->id; diff --git a/calendar/lib.php b/calendar/lib.php index f8d8e644b93..d23d7384d7d 100644 --- a/calendar/lib.php +++ b/calendar/lib.php @@ -1429,12 +1429,7 @@ function calendar_get_default_courses($ignoreref = false) { } } - if (isset($CFG->adminseesall)) { - $courses = get_my_courses($USER->id, null, null, $CFG->adminseesall); - } - else { - $courses = get_my_courses($USER->id, null, null, false); - } + $courses = enrol_get_my_courses(); return $courses; } diff --git a/calendar/view.php b/calendar/view.php index a0bd998951e..b455c916baa 100644 --- a/calendar/view.php +++ b/calendar/view.php @@ -636,7 +636,7 @@ function calendar_course_filter_selector($getvars = '') { if (has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_SYSTEM)) && !empty($CFG->calendar_adminseesall)) { $courses = get_courses('all', 'c.shortname','c.id,c.shortname'); } else { - $courses = get_my_courses($USER->id, 'shortname'); + $courses = enrol_get_my_courses(); } unset($courses[SITEID]); diff --git a/cohort/edit.php b/cohort/edit.php index 94798a1427d..d901575ce60 100644 --- a/cohort/edit.php +++ b/cohort/edit.php @@ -26,6 +26,7 @@ */ require('../config.php'); +require($CFG->dirroot.'/course/lib.php'); require($CFG->dirroot.'/cohort/lib.php'); require($CFG->dirroot.'/cohort/edit_form.php'); diff --git a/cohort/lib.php b/cohort/lib.php index caffeb757db..060c6015f52 100644 --- a/cohort/lib.php +++ b/cohort/lib.php @@ -28,25 +28,56 @@ require_once($CFG->dirroot . '/user/selector/lib.php'); /** * Add new cohort. - * @param object $data - * @return void + * + * @param object $cohort + * @return int */ -function cohort_add_cohort($data) { +function cohort_add_cohort($cohort) { global $DB; - $data->timecreated = time(); - $data->timemodified = $data->timecreated; - $DB->insert_record('cohort', $data); + + if (!isset($cohort->name)) { + throw new coding_excetion('Missing cohort name in cohort_add_cohort().'); + } + if (!isset($cohort->idnumber)) { + $cohort->idnumber = NULL; + } + if (!isset($cohort->description)) { + $cohort->description = $DB->sql_empty(); + } + if (!isset($cohort->descriptionformat)) { + $cohort->descriptionformat = FORMAT_HTML; + } + if (empty($cohort->component)) { + $cohort->component = ''; + } + if (!isset($cohort->timecreated)) { + $cohort->timecreated = time(); + } + if (!isset($cohort->timemodified)) { + $cohort->timemodified = $cohort->timecreated; + } + + $cohort->id = $DB->insert_record('cohort', $cohort); + + events_trigger('cohort_added', $cohort); + + return $cohort->id; } /** * Update existing cohort. - * @param object $data + * @param object $cohort * @return void */ -function cohort_update_cohort($data) { +function cohort_update_cohort($cohort) { global $DB; - $data->timemodified = time(); - $DB->update_record('cohort', $data); + if (isset($cohort->component) and empty($cohort->component)) { + $cohort->component = NULL; + } + $cohort->timemodified = time(); + $DB->update_record('cohort', $cohort); + + events_trigger('cohort_updated', $cohort); } /** @@ -63,6 +94,8 @@ function cohort_delete_cohort($cohort) { $DB->delete_records('cohort_members', array('cohortid'=>$cohort->id)); $DB->delete_records('cohort', array('id'=>$cohort->id)); + + events_trigger('cohort_deleted', $cohort); } /** @@ -104,6 +137,8 @@ function cohort_add_member($cohortid, $userid) { $record->userid = $userid; $record->timeadded = time(); $DB->insert_record('cohort_members', $record); + + events_trigger('cohort_member_added', (object)array('cohortid'=>$cohortid, 'userid'=>$userid)); } /** @@ -115,6 +150,8 @@ function cohort_add_member($cohortid, $userid) { function cohort_remove_member($cohortid, $userid) { global $DB; $DB->delete_records('cohort_members', array('cohortid'=>$cohortid, 'userid'=>$userid)); + + events_trigger('cohort_member_removed', (object)array('cohortid'=>$cohortid, 'userid'=>$userid)); } /** @@ -268,7 +305,7 @@ class cohort_existing_selector extends user_selector_base { return array($groupname => $availableusers); } - + protected function get_options() { $options = parent::get_options(); $options['cohortid'] = $this->cohortid; diff --git a/course/category.php b/course/category.php index 65db242d9cb..2b9128ab41d 100644 --- a/course/category.php +++ b/course/category.php @@ -112,9 +112,8 @@ if ($course) { $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); require_capability('moodle/course:visibility', $coursecontext); - if (!$DB->set_field('course', 'visible', $visible, array('id' => $course->id))) { - print_error('errorupdatingcoursevisibility'); - } + $DB->set_field('course', 'visible', $visible, array('id' => $course->id)); + $DB->set_field('course', 'visibleold', $visible, array('id' => $course->id)); // we set the old flag when user manually changes visibility of course } } @@ -244,7 +243,7 @@ /// Print out all the courses $courses = get_courses_page($category->id, 'c.sortorder ASC', - 'c.id,c.sortorder,c.shortname,c.fullname,c.summary,c.visible,c.guest,c.password', + 'c.id,c.sortorder,c.shortname,c.fullname,c.summary,c.visible', $totalcount, $page*$perpage, $perpage); $numcourses = count($courses); @@ -274,7 +273,6 @@ $strshow = get_string('show'); $strsummary = get_string('summary'); $strsettings = get_string('settings'); - $strassignteachers = get_string('assignteachers'); $strallowguests = get_string('allowguests'); $strrequireskey = get_string('requireskey'); @@ -401,16 +399,7 @@ echo ''; } else { echo ''; - if (!empty($acourse->guest)) { - echo ''.$strallowguests.''; - } - if (!empty($acourse->password)) { - echo ''.$strrequireskey.''; - } + //TODO: show some icons for plugins - such as guest, pasword, etc. if (!empty($acourse->summary)) { $link = new moodle_url("/course/info.php?id=$acourse->id"); echo $OUTPUT->action_link($link, ''.get_string('info').'', diff --git a/course/edit.php b/course/edit.php index 2d8a045702e..17882a80072 100644 --- a/course/edit.php +++ b/course/edit.php @@ -1,165 +1,159 @@ dirroot.'/enrol/enrol.class.php'); - require_once('lib.php'); - require_once('edit_form.php'); +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . - $id = optional_param('id', 0, PARAM_INT); // course id - $categoryid = optional_param('category', 0, PARAM_INT); // course category - can be changed in edit form +/** + * Edit course settings + * + * @package moodlecore + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ - $PAGE->set_pagelayout('admin'); +require_once('../config.php'); +require_once('lib.php'); +require_once('edit_form.php'); -/// basic access control checks - if ($id) { // editing course +$id = optional_param('id', 0, PARAM_INT); // course id +$categoryid = optional_param('category', 0, PARAM_INT); // course category - can be changed in edit form - if($id == SITEID){ - // don't allow editing of 'site course' using this from - print_error('cannoteditsiteform'); - } +$PAGE->set_pagelayout('admin'); +$PAGE->set_url('/course/edit.php'); - if (!$course = $DB->get_record('course', array('id'=>$id))) { - print_error('invalidcourseid'); - } - require_login($course->id); - $category = $DB->get_record('course_categories', array('id'=>$course->category)); - $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); - require_capability('moodle/course:update', $coursecontext); - } else if ($categoryid) { // creating new course in this category - $course = null; - require_login(); - if (!$category = $DB->get_record('course_categories', array('id'=>$categoryid))) { - print_error('unknowcategory'); - } - require_capability('moodle/course:create', get_context_instance(CONTEXT_COURSECAT, $category->id)); - } else { - require_login(); - print_error('needcoursecategroyid'); +// basic access control checks +if ($id) { // editing course + if ($id == SITEID){ + // don't allow editing of 'site course' using this from + print_error('cannoteditsiteform'); } - $PAGE->set_url('/course/edit.php'); - if ($id !== 0) { - $PAGE->url->param('id',$id); + $course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); + require_login($course->id); + $category = $DB->get_record('course_categories', array('id'=>$course->category), '*', MUST_EXIST); + $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); + require_capability('moodle/course:update', $coursecontext); + $PAGE->url->param('id',$id); + +} else if ($categoryid) { // creating new course in this category + $course = null; + require_login(); + $category = $DB->get_record('course_categories', array('id'=>$categoryid), '*', MUST_EXIST); + require_capability('moodle/course:create', get_context_instance(CONTEXT_COURSECAT, $category->id)); + $PAGE->url->param('category',$categoryid); + +} else { + require_login(); + print_error('needcoursecategroyid'); +} + +// Prepare course and the editor +$editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes'=>$CFG->maxbytes, 'trusttext'=>false, 'noclean'=>true); +if (!empty($course)) { + $allowedmods = array(); + if ($am = $DB->get_records('course_allowed_modules', array('course'=>$course->id))) { + foreach ($am as $m) { + $allowedmods[] = $m->module; + } } else { - $PAGE->url->param('category',$categoryid); + // this happens in case we edit course created before enabling module restrictions or somebody disabled everything :-( + if (empty($course->restrictmodules) and !empty($CFG->defaultallowedmodules)) { + $allowedmods = explode(',', $CFG->defaultallowedmodules); + } + } + $course->allowedmods = $allowedmods; + $course = file_prepare_standard_editor($course, 'summary', $editoroptions, $coursecontext, 'course_summary', 0); + +} else { + $course = file_prepare_standard_editor($course, 'summary', $editoroptions, null, 'course_summary', null); +} + +// first create the form +$editform = new course_edit_form(NULL, array('course'=>$course, 'category'=>$category, 'editoroptions'=>$editoroptions)); + +if ($editform->is_cancelled()) { + if (empty($course)) { + redirect($CFG->wwwroot.'/'); + } else { + redirect($CFG->wwwroot.'/course/view.php?id='.$course->id); } - /// Prepare course and the editor - $editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes'=>$CFG->maxbytes, 'trusttext'=>false, 'noclean'=>true); - if (!empty($course)) { - $allowedmods = array(); - if (!empty($course)) { - if ($am = $DB->get_records('course_allowed_modules', array('course'=>$course->id))) { - foreach ($am as $m) { - $allowedmods[] = $m->module; +} else if ($data = $editform->get_data()) { + // process data if submitted + + if (empty($course->id)) { + // In creating the course + $course = create_course($data, $editoroptions); + + // Get the context of the newly created course + $context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + + // try to deal with course creators - enrol them internally with default role + if (!empty($CFG->creatornewroleid) and !is_viewing($context, NULL, 'moodle/role:assign') and !is_enrolled($context, NULL, 'moodle/role:assign')) { + enrol_try_internal_enrol($course->id, $USER->id, $CFG->creatornewroleid); + } + + // Redirect to manual enrolment page if possible + $instances = enrol_get_instances($course->id, true); + foreach($instances as $instance) { + if ($plugin = enrol_get_plugin($instance->enrol)) { + if ($link = $plugin->get_manual_enrol_link($instance)) { + redirect($link); } - } else { - if (empty($course->restrictmodules)) { - $allowedmods = explode(',',$CFG->defaultallowedmodules); - } // it'll be greyed out but we want these by default anyway. } - $course->allowedmods = $allowedmods; } - $course = file_prepare_standard_editor($course, 'summary', $editoroptions, $coursecontext, 'course_summary', $course->id); + + redirect($CFG->wwwroot."/course/view.php?id=$course->id"); + } else { - $course = file_prepare_standard_editor($course, 'summary', $editoroptions, null, 'course_summary', null); - } - -/// first create the form - $editform = new course_edit_form('edit.php', compact('course', 'category', 'editoroptions')); - // now override defaults if course already exists - if (!empty($course->id)) { - $course->enrolpassword = $course->password; // we need some other name for password field MDL-9929 - $editform->set_data($course); - } - if ($editform->is_cancelled()){ - if (empty($course)) { - redirect($CFG->wwwroot); - } else { - redirect($CFG->wwwroot.'/course/view.php?id='.$course->id); - } - - } else if ($data = $editform->get_data()) { - - $data->password = $data->enrolpassword; // we need some other name for password field MDL-9929 -/// process data if submitted - - //preprocess data - $data->timemodified = time(); - - if (empty($course->id)) { - // In creating the course - if (!$course = create_course($data)) { - print_error('coursenotcreated'); - } - - // Get the context of the newly created course - $context = get_context_instance(CONTEXT_COURSE, $course->id); - - // Save the files used in the summary editor - $editordata = new stdClass; - $editordata->id = $course->id; - $editordata->summary_editor = $data->summary_editor; - $editordata = file_postupdate_standard_editor($editordata, 'summary', $editoroptions, $context, 'course_summary', $course->id); - $DB->update_record('course', $editordata); - - // assign default role to creator if not already having permission to manage course assignments - if (!is_viewing($context, NULL, 'moodle/role:assign') and !is_enrolled($context, NULL, 'moodle/role:assign')) { - role_assign($CFG->creatornewroleid, $USER->id, 0, $context->id); - } - - // ensure we can use the course right after creating it - // this means trigger a reload of accessinfo... - mark_context_dirty($context->path); - - if ($data->metacourse and has_capability('moodle/course:managemetacourse', $context)) { - // Redirect users with metacourse capability to student import - redirect($CFG->wwwroot."/course/importstudents.php?id=$course->id"); - } else { - // Redirect to roles assignment - redirect($CFG->wwwroot."/$CFG->admin/roles/assign.php?contextid=$context->id"); - } - - } else { - // Save any changes to the files used in the editor - $data = file_postupdate_standard_editor($data, 'summary', $editoroptions, $coursecontext, 'course_summary', $data->id); - if (!update_course($data)) { - print_error('coursenotupdated'); - } - redirect($CFG->wwwroot."/course/view.php?id=$course->id"); - } + // Save any changes to the files used in the editor + update_course($data, $editoroptions); + redirect($CFG->wwwroot."/course/view.php?id=$course->id"); } +} -/// Print the form +// Print the form - $site = get_site(); +$site = get_site(); - $streditcoursesettings = get_string("editcoursesettings"); - $straddnewcourse = get_string("addnewcourse"); - $stradministration = get_string("administration"); - $strcategories = get_string("categories"); +$streditcoursesettings = get_string("editcoursesettings"); +$straddnewcourse = get_string("addnewcourse"); +$stradministration = get_string("administration"); +$strcategories = get_string("categories"); - if (!empty($course->id)) { - $PAGE->navbar->add($streditcoursesettings); - $title = $streditcoursesettings; - $fullname = $course->fullname; - } else { - $PAGE->navbar->add($stradministration, new moodle_url('/admin/index.php')); - $PAGE->navbar->add($strcategories, new moodle_url('/course/index.php')); - $PAGE->navbar->add($straddnewcourse); - $title = "$site->shortname: $straddnewcourse"; - $fullname = $site->fullname; - } +if (!empty($course->id)) { + $PAGE->navbar->add($streditcoursesettings); + $title = $streditcoursesettings; + $fullname = $course->fullname; +} else { + $PAGE->navbar->add($stradministration, new moodle_url('/admin/index.php')); + $PAGE->navbar->add($strcategories, new moodle_url('/course/index.php')); + $PAGE->navbar->add($straddnewcourse); + $title = "$site->shortname: $straddnewcourse"; + $fullname = $site->fullname; +} - $PAGE->set_title($title); - $PAGE->set_heading($fullname); - $PAGE->set_focuscontrol($editform->focus()); - echo $OUTPUT->header(); - echo $OUTPUT->heading($streditcoursesettings); +$PAGE->set_title($title); +$PAGE->set_heading($fullname); +$PAGE->set_focuscontrol($editform->focus()); - $editform->display(); +echo $OUTPUT->header(); +echo $OUTPUT->heading($streditcoursesettings); - echo $OUTPUT->footer(); +$editform->display(); + +echo $OUTPUT->footer(); diff --git a/course/edit_form.php b/course/edit_form.php index b3ee3e293f6..f69f1b20314 100644 --- a/course/edit_form.php +++ b/course/edit_form.php @@ -1,83 +1,73 @@ libdir.'/formslib.php'); class course_edit_form extends moodleform { + protected $course; + protected $context; function definition() { global $USER, $CFG, $DB; - $courseconfig = get_config('moodlecourse'); - $mform =& $this->_form; + $mform = $this->_form; - $course = $this->_customdata['course']; - $category = $this->_customdata['category']; + $course = $this->_customdata['course']; // this contains the data of this form + $category = $this->_customdata['category']; $editoroptions = $this->_customdata['editoroptions']; - $systemcontext = get_context_instance(CONTEXT_SYSTEM); + $systemcontext = get_context_instance(CONTEXT_SYSTEM); $categorycontext = get_context_instance(CONTEXT_COURSECAT, $category->id); - $disable_meta = false; // basic meta course state protection; server-side security checks not needed if (!empty($course->id)) { $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); $context = $coursecontext; - - if (course_in_meta($course)) { - $disable_meta = get_string('metaalreadyinmeta'); - - } else if ($course->metacourse) { - if ($DB->count_records('course_meta', array('parent_course'=>$course->id)) > 0) { - $disable_meta = get_string('metaalreadyhascourses'); - } - - } else { - // if users already enrolled directly into coures, do not allow switching to meta, - // users with metacourse manage permission are exception - // please note that we do not need exact results - anything unexpected here prevents metacourse - $managers = get_users_by_capability($coursecontext, 'moodle/course:managemetacourse', 'u.id'); - $enrolroles = get_roles_with_capability('moodle/course:participate', CAP_ALLOW, $coursecontext); - if ($users = get_role_users(array_keys($enrolroles), $coursecontext, false, 'u.id', 'u.id ASC')) { - foreach($users as $user) { - if (!isset($managers[$user->id])) { - $disable_meta = get_string('metaalreadyhasenrolments'); - break; - } - } - } - unset($managers); - unset($users); - unset($enrolroles); - } } else { $coursecontext = null; $context = $categorycontext; } + $courseconfig = get_config('moodlecourse'); + + $this->course = $course; + $this->context = $context; + /// form definition with new course defaults //-------------------------------------------------------------------------------- $mform->addElement('header','general', get_string('general', 'form')); - // Must have create course capability in both categories in order to move course - if (has_capability('moodle/course:create', $categorycontext)) { - $displaylist = array(); - $parentlist = array(); - make_categories_list($displaylist, $parentlist, 'moodle/course:create'); - $mform->addElement('select', 'category', get_string('category'), $displaylist); + // verify permissions to change course category or keep current + if (empty($course->id)) { + if (has_capability('moodle/course:create', $categorycontext)) { + $displaylist = array(); + $parentlist = array(); + make_categories_list($displaylist, $parentlist, 'moodle/course:create'); + $mform->addElement('select', 'category', get_string('category'), $displaylist); + $mform->addHelpButton('category', 'category'); + $mform->setDefault('category', $category->id); + } else { + $mform->addElement('hidden', 'category', null); + $mform->setType('category', PARAM_INT); + $mform->setConstant('category', $category->id); + } } else { - $mform->addElement('hidden', 'category', null); - $mform->setType('category', PARAM_INT); - } - $mform->addHelpButton('category', 'category'); - $mform->setDefault('category', $category->id); - $mform->setType('category', PARAM_INT); - - if (!empty($course->id) and !has_capability('moodle/course:changecategory', $coursecontext)) { - $mform->hardFreeze('category'); - $mform->setConstant('category', $category->id); + if (has_capability('moodle/course:changecategory', $coursecontext)) { + $displaylist = array(); + $parentlist = array(); + make_categories_list($displaylist, $parentlist, 'moodle/course:create'); + if (!isset($displaylist[$course->category])) { + //always keep current + $displaylist[$course->category] = format_string($DB->get_field('course_categories', 'name', array('id'=>$course->category))); + } + $mform->addElement('select', 'category', get_string('category'), $displaylist); + $mform->addHelpButton('category', 'category'); + } else { + //keep current + $mform->addElement('hidden', 'category', null); + $mform->setType('category', PARAM_INT); + $mform->setConstant('category', $course->category); + } } $mform->addElement('text','fullname', get_string('fullnamecourse'),'maxlength="254" size="50"'); @@ -175,106 +165,8 @@ class course_edit_form extends moodleform { $mform->addElement('select', 'theme', get_string('forcetheme'), $themes); } - $meta=array(); - $meta[0] = get_string('no'); - $meta[1] = get_string('yes'); - if ($disable_meta === false) { - $mform->addElement('select', 'metacourse', get_string('managemeta'), $meta); - $mform->addHelpButton('metacourse', 'managemeta'); - $mform->setDefault('metacourse', $courseconfig->metacourse); - } else { - // no metacourse element - we do not want to change it anyway! - $mform->addElement('static', 'nometacourse', get_string('managemeta'), - ((empty($course->metacourse)) ? $meta[0] : $meta[1]) . " - $disable_meta "); - $mform->addHelpButton('nometacourse', 'managemeta'); - } - //-------------------------------------------------------------------------------- - $mform->addElement('header','enrolhdr', get_string('enrolments')); - - $choices = array(); - $modules = explode(',', $CFG->enrol_plugins_enabled); - foreach ($modules as $module) { - $name = get_string('enrolname', "enrol_$module"); - $plugin = enrolment_factory::factory($module); - if (method_exists($plugin, 'print_entry')) { - $choices[$name] = $module; - } - } - asort($choices); - $choices = array_flip($choices); - $choices = array_merge(array('' => get_string('sitedefault').' ('.get_string('enrolname', "enrol_$CFG->enrol").')'), $choices); - $mform->addElement('select', 'enrol', get_string('enrolmentplugins'), $choices); - $mform->addHelpButton('enrol', 'enrolmentplugins'); - $mform->setDefault('enrol', $courseconfig->enrol); - - - $roles = get_assignable_roles($context); - if (!empty($course->id)) { - // add current default role, so that it is selectable even when user can not assign it - if ($current_role = $DB->get_record('role', array('id'=>$course->defaultrole))) { - $roles[$current_role->id] = strip_tags(format_string($current_role->name, true)); - } - } - $choices = array(); - if ($sitedefaultrole = $DB->get_record('role', array('id'=>$CFG->defaultcourseroleid))) { - $choices[0] = get_string('sitedefault').' ('.$sitedefaultrole->name.')'; - } else { - $choices[0] = get_string('sitedefault'); - } - $choices = $choices + $roles; - - // fix for MDL-9197 - foreach ($choices as $choiceid => $choice) { - $choices[$choiceid] = format_string($choice); - } - - $mform->addElement('select', 'defaultrole', get_string('defaultrole', 'role'), $choices); - $mform->setDefault('defaultrole', 0); - - - $radio = array(); - $radio[] = &MoodleQuickForm::createElement('radio', 'enrollable', null, get_string('no'), 0); - $radio[] = &MoodleQuickForm::createElement('radio', 'enrollable', null, get_string('yes'), 1); - $radio[] = &MoodleQuickForm::createElement('radio', 'enrollable', null, get_string('enroldate'), 2); - $mform->addGroup($radio, 'enrollable', get_string('enrollable'), ' ', false); - $mform->addHelpButton('enrollable', 'enrollable'); - $mform->setDefault('enrollable', $courseconfig->enrollable); - - $mform->addElement('date_selector', 'enrolstartdate', get_string('enrolstartdate'), array('optional' => true)); - $mform->setDefault('enrolstartdate', 0); - $mform->disabledIf('enrolstartdate', 'enrollable', 'neq', 2); - - $mform->addElement('date_selector', 'enrolenddate', get_string('enrolenddate'), array('optional' => true)); - $mform->setDefault('enrolenddate', 0); - $mform->disabledIf('enrolenddate', 'enrollable', 'neq', 2); - - $mform->addElement('duration', 'enrolperiod', get_string('enrolperiod'), array('optional' => true, 'defaultunit' => 86400)); - $mform->setDefault('enrolperiod', $courseconfig->enrolperiod); - - -//-------------------------------------------------------------------------------- - $mform->addElement('header','expirynotifyhdr', get_string('expirynotify')); - - $choices = array(); - $choices['0'] = get_string('no'); - $choices['1'] = get_string('yes'); - $mform->addElement('select', 'expirynotify', get_string('notify'), $choices); - $mform->addHelpButton('expirynotify', 'notify'); - $mform->setDefault('expirynotify', $courseconfig->expirynotify); - - $mform->addElement('select', 'notifystudents', get_string('expirynotifystudents'), $choices); - $mform->addHelpButton('notifystudents', 'expirynotifystudents'); - $mform->setDefault('notifystudents', $courseconfig->notifystudents); - - $thresholdmenu=array(); - for ($i=1; $i<=30; $i++) { - $seconds = $i * 86400; - $thresholdmenu[$seconds] = get_string('numdays', '', $i); - } - $mform->addElement('select', 'expirythreshold', get_string('expirythreshold'), $thresholdmenu); - $mform->addHelpButton('expirythreshold', 'expirythreshold'); - $mform->setDefault('expirythreshold', $courseconfig->expirythreshold); + enrol_course_edit_form($mform, $course, $context); //-------------------------------------------------------------------------------- $mform->addElement('header','', get_string('groups', 'group')); @@ -313,48 +205,6 @@ class course_edit_form extends moodleform { $mform->setConstant('visible', $course->visible); } - $mform->addElement('passwordunmask', 'enrolpassword', get_string('enrolmentkey'), 'size="25"'); - $mform->setDefault('enrolpassword', ''); - $mform->setDefault('enrolpassword', $courseconfig->enrolpassword); - $mform->setType('enrolpassword', PARAM_RAW); - - if (empty($course->id) or ($course->password !== '' and $course->id != SITEID)) { - // do not require password in existing courses that do not have password yet - backwards compatibility ;-) - if (!empty($CFG->enrol_manual_requirekey)) { - $mform->addRule('enrolpassword', get_string('required'), 'required', null, 'client'); - } - } - - $choices = array(); - $choices['0'] = get_string('guestsno'); - $choices['1'] = get_string('guestsyes'); - $choices['2'] = get_string('guestskey'); - $mform->addElement('select', 'guest', get_string('opentoguests'), $choices); - $mform->setDefault('guest', $courseconfig->guest); - - // If we are creating a course, its enrol method isn't yet chosen, BUT the site has a default enrol method which we can use here - $enrol_object = $CFG; - if (!empty($course->id)) { - $enrol_object = $course; - } - // If the print_entry method exists and the course enrol method isn't manual (both set or inherited from site), show cost - if (method_exists(enrolment_factory::factory($enrol_object->enrol), 'print_entry') && !($enrol_object->enrol == 'manual' || (empty($enrol_object->enrol) && $CFG->enrol == 'manual'))) { - $costgroup=array(); - $currencies = get_string_manager()->get_list_of_currencies(); - $costgroup[]= &MoodleQuickForm::createElement('text','cost', '', 'maxlength="6" size="6"'); - $costgroup[]= &MoodleQuickForm::createElement('select', 'currency', '', $currencies); - $mform->addGroup($costgroup, 'costgrp', get_string('cost'), ' ', false); - //defining a rule for a form element within a group : - $costgrprules=array(); - //set the message to null to tell Moodle to use a default message - //available for most rules, fetched from language pack (err_{rulename}). - $costgrprules['cost'][]=array(null, 'numeric', null, 'client'); - $mform->addGroupRule('costgrp',$costgrprules); - $mform->setDefault('cost', ''); - $mform->setDefault('currency', empty($CFG->enrol_currency) ? 'USD' : $CFG->enrol_currency); - - } - //-------------------------------------------------------------------------------- $mform->addElement('header','', get_string('language')); @@ -386,31 +236,38 @@ class course_edit_form extends moodleform { } //-------------------------------------------------------------------------------- - if (has_capability('moodle/site:config', $systemcontext) && ((!empty($course->requested) && $CFG->restrictmodulesfor == 'requested') || $CFG->restrictmodulesfor == 'all')) { - $mform->addElement('header', '', get_string('restrictmodules')); + if (has_capability('moodle/site:config', $systemcontext)) { + if (((!empty($course->requested) && $CFG->restrictmodulesfor == 'requested') || $CFG->restrictmodulesfor == 'all')) { + $mform->addElement('header', '', get_string('restrictmodules')); - $options = array(); - $options['0'] = get_string('no'); - $options['1'] = get_string('yes'); - $mform->addElement('select', 'restrictmodules', get_string('restrictmodules'), $options); - $mods = array(0=>get_string('allownone')); - $mods += $DB->get_records_menu('modules', array(), 'name', 'id, name'); + $options = array(); + $options['0'] = get_string('no'); + $options['1'] = get_string('yes'); + $mform->addElement('select', 'restrictmodules', get_string('restrictmodules'), $options); + if (!empty($CFG->restrictbydefault)) { + $mform->setDefault('restrictmodules', 1); + } - - $mform->addElement('select', 'allowedmods', get_string('to'), $mods, - array('multiple'=>'multiple', 'size'=>'10')); - $mform->disabledIf('allowedmods', 'restrictmodules', 'eq', 0); + $mods = array(0=>get_string('allownone')); + $mods += $DB->get_records_menu('modules', array('visible'=>1), 'name', 'id, name'); + $mform->addElement('select', 'allowedmods', get_string('to'), $mods, array('multiple'=>'multiple', 'size'=>'10')); + $mform->disabledIf('allowedmods', 'restrictmodules', 'eq', 0); + // defaults are already in $course + } else { + // remove any mod restriction + $mform->addElement('hidden', 'restrictmodules', 0); + $mform->setType('restrictmodules', PARAM_INT); + } } else { - $mform->addElement('hidden', 'restrictmodules', null); + $mform->addElement('hidden', 'restrictmodules'); $mform->setType('restrictmodules', PARAM_INT); - } - if ($CFG->restrictmodulesfor == 'all') { - $mform->setDefault('allowedmods', explode(',',$CFG->defaultallowedmodules)); - if (!empty($CFG->restrictbydefault)) { - $mform->setDefault('restrictmodules', 1); + if (empty($course->id)) { + $mform->setConstant('restrictmodules', (int)($CFG->restrictmodulesfor == 'all')); + } else { + // keep previous + $mform->setConstant('restrictmodules', $course->restrictmodules); } } - $mform->setType('restrictmodules', PARAM_INT); /// customizable role names in this course //-------------------------------------------------------------------------------- @@ -439,14 +296,18 @@ class course_edit_form extends moodleform { //-------------------------------------------------------------------------------- $mform->addElement('hidden', 'id', null); $mform->setType('id', PARAM_INT); + +/// finally set the current form data +//-------------------------------------------------------------------------------- + $this->set_data($course); } function definition_after_data() { global $DB; - $mform =& $this->_form; + $mform = $this->_form; - // add availabe groupings + // add available groupings if ($courseid = $mform->getElementValue('id') and $mform->elementExists('defaultgroupingid')) { $options = array(); if ($groupings = $DB->get_records('groupings', array('courseid'=>$courseid))) { @@ -478,21 +339,7 @@ class course_edit_form extends moodleform { } } - if (!empty($data['enrolstartdate']) && !empty($data['enrolenddate']) && - $data['enrolenddate'] <= $data['enrolstartdate']){ - $errors['enrolenddate'] = get_string('enrolenddaterror'); - } - - if (!empty($CFG->enrol_manual_usepasswordpolicy) and isset($data['enrolpassword']) and $data['enrolpassword'] != '') { - $course = $this->_customdata['course']; - if ($course->password !== $data['enrolpassword']) { - // enforce password policy only if changing password - backwards compatibility - $errmsg = ''; - if (!check_password_policy($data['enrolpassword'], $errmsg)) { - $errors['enrolpassword'] = $errmsg; - } - } - } + $errors = array_merge($errors, enrol_course_edit_validation($data, $this->context)); return $errors; } diff --git a/course/enrol.php b/course/enrol.php index f7808982a8d..aceb88b9555 100644 --- a/course/enrol.php +++ b/course/enrol.php @@ -16,118 +16,15 @@ // along with Moodle. If not, see . /** - * Depending on the current enrolment method, this page - * presents the user with whatever they need to know when - * they try to enrol in a course. + * Redirection of old enrol entry point. * * @copyright 1999 Martin Dougiamas http://dougiamas.com * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package course */ -require_once("../config.php"); -require_once("lib.php"); -require_once("$CFG->dirroot/enrol/enrol.class.php"); +require('../config.php'); -$id = required_param('id', PARAM_INT); -$loginasguest = optional_param('loginasguest', 0, PARAM_BOOL); // hmm, is this still needed? - -$url = new moodle_url('/course/enrol.php', array('id'=>$id)); -if ($loginasguest !== 0) { - $url->param('loginasguest', $loginasguest); -} -$PAGE->set_url($url); - -if (!isloggedin()) { - // do not use require_login here because we are usually comming from it - redirect(get_login_url()); -} - -if (!$course = $DB->get_record('course', array('id'=>$id))) { - print_error("That's an invalid course id"); -} - -if (! $context = get_context_instance(CONTEXT_COURSE, $course->id) ) { - print_error("That's an invalid course id"); -} - -/// do not use when in course login as -if (session_is_loggedinas() and $USER->loginascontext->contextlevel == CONTEXT_COURSE) { - print_error('loginasnoenrol', '', $CFG->wwwroot.'/course/view.php?id='.$USER->loginascontext->instanceid); -} - -$enrol = enrolment_factory::factory($course->enrol); // do not use if (!$enrol... here, it can not work in PHP4 - see MDL-7529 - -/// Refreshing all current role assignments for the current user - -load_all_capabilities(); - -/// Double check just in case they are actually enrolled already and -/// thus got to this script by mistake. This might occur if enrolments -/// changed during this session or something - -if (has_capability('moodle/course:participate', $context)) { - if (!empty($SESSION->wantsurl)) { - $destination = $SESSION->wantsurl; - unset($SESSION->wantsurl); - } else { - $destination = "$CFG->wwwroot/course/view.php?id=$course->id"; - } - redirect($destination); // Bye! -} - -/// Check if the course is a meta course (bug 5734) -if ($course->metacourse) { - echo $OUTPUT->header(); - notice(get_string('coursenotaccessible'), "$CFG->wwwroot/index.php"); -} - -/// Users can't enroll to site course -if ($course->id == SITEID) { - echo $OUTPUT->header(); - notice(get_string('enrollfirst'), "$CFG->wwwroot/index.php"); -} - -/// Double check just in case they are enrolled to start in the future - -if ($course->enrolperiod) { // Only active if the course has an enrolment period in effect - if ($roles = get_user_roles($context, $USER->id)) { - foreach ($roles as $role) { - if ($role->timestart and ($role->timestart >= time())) { - $message = get_string('enrolmentnotyet', '', userdate($student->timestart)); - echo $OUTPUT->header(); - notice($message, "$CFG->wwwroot/index.php"); - } - } - } -} - -/// Check if the course is enrollable -if (!method_exists($enrol, 'print_entry')) { - echo $OUTPUT->header(); - notice(get_string('enrolmentnointernal'), "$CFG->wwwroot/index.php"); -} - -if (!$course->enrollable || - ($course->enrollable == 2 && $course->enrolstartdate > 0 && $course->enrolstartdate > time()) || - ($course->enrollable == 2 && $course->enrolenddate > 0 && $course->enrolenddate <= time()) - ) { - $PAGE->set_title($course->shortname); - $PAGE->set_heading($course->fullname); - $PAGE->navbar->add($course->shortname); - echo $OUTPUT->header(); - notice(get_string('notenrollable'), "$CFG->wwwroot/index.php"); -} - -/// Check the submitted enrolment information if there is any (eg could be enrolment key) - -if ($form = data_submitted()) { - $enrol->check_entry($form, $course); // Should terminate/redirect in here if it's all OK -} - -/// Otherwise, we print the entry form. - -$enrol->print_entry($course); - -/// Easy! +$id = required_param('id', PARAM_INT); +redirect(new moodle_url('/enrol/index.php', array('id'=>$id))); diff --git a/course/external.php b/course/external.php deleted file mode 100644 index 660f6f81d7f..00000000000 --- a/course/external.php +++ /dev/null @@ -1,749 +0,0 @@ -id - the id to search - * @subparam string $params:search->idnumber - the idnumber to search - * @subparam string $params:search->shortname - the shortname to search - * @return object $return - * @subreturn integer $return:course->id - * @subreturn string $return:course->idnumber - * @subreturn string $return:course->shortname - * @subreturn integer $return:course->category - * @subreturn string $return:course->fullname - * @subreturn string $return:course->summary - * @subreturn string $return:course->format - * @subreturn integer $return:course->startdate - * @subreturn integer $return:course->sortorder - * @subreturn integer $return:course->showgrades - * @subreturn string $return:course->modinfo - * @subreturn string $return:course->newsitems - * @subreturn string $return:course->guest - * @subreturn integer $return:course->metacourse - * @subreturn string $return:course->password - * @subreturn integer $return:course->enrolperiod - * @subreturn integer $return:course->defaultrole - * @subreturn integer $return:course->enrollable - * @subreturn integer $return:course->numsections - * @subreturn integer $return:course->expirynotify - * @subreturn integer $return:course->notifystudents - * @subreturn integer $return:course->expirythreshold - * @subreturn integer $return:course->marker - * @subreturn integer $return:course->maxbytes - * @subreturn integer $return:course->showreports - * @subreturn integer $return:course->visible - * @subreturn integer $return:course->hiddensections - * @subreturn integer $return:course->groupmode - * @subreturn integer $return:course->groupmodeforce - * @subreturn integer $return:course->defaultgroupingid - * @subreturn string $return:course->lang - * @subreturn string $return:course->theme - * @subreturn string $return:course->cost - * @subreturn string $return:course->currency - * @subreturn integer $return:course->timecreated - * @subreturn integer $return:course->timemodified - * @subreturn integer $return:course->requested - * @subreturn integer $return:course->restrictmodules - * @subreturn integer $return:course->enrolstartdate - * @subreturn integer $return:course->enrolenddate - * @subreturn string $return:course->enrol - * @subreturn integer $return:course->enablecompletion - */ - static function get_courses($params) { - global $USER, $DB; - if (has_capability('moodle/course:participate', get_context_instance(CONTEXT_SYSTEM))) { - $courses = array(); - foreach ($params as $param) { - $course = new stdClass(); - if (key_exists('id', $param)) { - $param['id'] = clean_param($param['id'], PARAM_INT); - $course = $DB->get_record('course', array('id'=>$param['id'])); - - } else if (key_exists('idnumber', $param)) { - $param['idnumber'] = clean_param($param['idnumber'], PARAM_ALPHANUM); - $course = $DB->get_record('course', array('idnumber'=>$param['idnumber'])); - } else if (key_exists('shortname', $param)) { - $param['shortname'] = clean_param($param['shortname'], PARAM_ALPHANUM); - $course = $DB->get_record('course', array('shortname'=>$param['shortname'])); - } - if (!empty($course)) { - $returnedcourse = new stdClass(); - $returnedcourse->id = $course->id; - $returnedcourse->idnumber = $course->idnumber; - $returnedcourse->shortname = $course->shortname; - $returnedcourse->summary = $course->summary; - $returnedcourse->format = $course->format; - $returnedcourse->fullname = $course->fullname; - $returnedcourse->numsections = $course->numsections; - $returnedcourse->startdate = $course->startdate; - $returnedcourse->category = $course->category; - $returnedcourse->sortorder = $course->sortorder; - $returnedcourse->password = $course->password ; - $returnedcourse->showgrades = $course->showgrades; - $returnedcourse->modinfo = $course->modinfo; - $returnedcourse->newsitems = $course->newsitems; - $returnedcourse->guest = $course->guest; - $returnedcourse->enrolperiod = $course->enrolperiod; - $returnedcourse->marker = $course->marker; - $returnedcourse->maxbytes = $course->maxbytes; - $returnedcourse->showreports = $course->showreports; - $returnedcourse->visible = $course->visible; - $returnedcourse->hiddensections = $course->hiddensections; - $returnedcourse->groupmode = $course->groupmode; - $returnedcourse->groupmodeforce = $course->groupmodeforce; - $returnedcourse->defaultgroupingid = $course->defaultgroupingid; - $returnedcourse->lang = $course->lang; - $returnedcourse->theme = $course->theme; - $returnedcourse->cost = $course->cost; - $returnedcourse->currency = $course->currency; - $returnedcourse->timecreated = $course->timecreated; - $returnedcourse->timemodified = $course->timemodified; - $returnedcourse->metacourse = $course->metacourse; - $returnedcourse->requested = $course->requested; - $returnedcourse->restrictmodules = $course->restrictmodules; - $returnedcourse->expirynotify = $course->expirynotify; - $returnedcourse->expirythreshold = $course->expirythreshold; - $returnedcourse->notifystudents = $course->notifystudents; - $returnedcourse->enrollable = $course->enrollable; - $returnedcourse->enrolstartdate = $course->enrolstartdate; - $returnedcourse->enrolenddate = $course->enrolenddate; - $returnedcourse->enrol = $course->enrol; - $returnedcourse->defaultrole = $course->defaultrole; - $returnedcourse->enablecompletion = $course->enablecompletion; - - $courses[] = $returnedcourse; - } - } - return $courses; - } - else { - throw new moodle_exception('wscouldnotviewcoursenopermission'); - } - } - - /** - * Create multiple courses - * @param array|struct $params - need to be define as struct for XMLRPC - * @subparam string $params:course->idnumber - * @subparam string $params:course->shortname - * @subparam integer $params:course->category - * @subparam string $params:course->fullname - * @subparam string $params:course->summary - * @subparam string $params:course->format - * @subparam integer $params:course->startdate - * @subparam integer $params:course->sortorder - * @subparam integer $params:course->showgrades - * @subparam string $params:course->modinfo - * @subparam string $params:course->newsitems - * @subparam string $params:course->guest - * @subparam integer $params:course->metacourse - * @subparam string $params:course->password - * @subparam integer $params:course->enrolperiod - * @subparam integer $params:course->defaultrole - * @subparam integer $params:course->enrollable - * @subparam integer $params:course->numsections - * @subparam integer $params:course->expirynotify - * @subparam integer $params:course->notifystudents - * @subparam integer $params:course->expirythreshold - * @subparam integer $params:course->marker - * @subparam integer $params:course->maxbytes - * @subparam integer $params:course->showreports - * @subparam integer $params:course->visible - * @subparam integer $params:course->hiddensections - * @subparam integer $params:course->groupmode - * @subparam integer $params:course->groupmodeforce - * @subparam integer $params:course->defaultgroupingid - * @subparam string $params:course->lang - * @subparam string $params:course->theme - * @subparam string $params:course->cost - * @subparam string $params:course->currency - * @subparam integer $params:course->timecreated - * @subparam integer $params:course->timemodified - * @subparam integer $params:course->requested - * @subparam integer $params:course->restrictmodules - * @subparam integer $params:course->enrolstartdate - * @subparam integer $params:course->enrolenddate - * @subparam string $params:course->enrol - * @subparam integer $params:course->enablecompletion - * @return array $return ids of new courses - * @subreturn integer $return:id course id - */ - static function create_courses($params) { - global $USER; - if (has_capability('moodle/course:create', get_context_instance(CONTEXT_SYSTEM))) { - $courses = array(); - foreach ($params as $courseparams) { - - $course = new stdClass(); - if (array_key_exists('idnumber', $courseparams)) { - $course->idnumber = clean_param($courseparams['idnumber'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('shortname', $courseparams)) { - $course->shortname = clean_param($courseparams['shortname'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('category', $courseparams)) { - $course->category = clean_param($courseparams['category'], PARAM_INT); - } - - if (array_key_exists('fullname', $courseparams)) { - $course->fullname = clean_param($courseparams['fullname'], PARAM_TEXT); - } - - if (array_key_exists('summary', $courseparams)) { - $course->summary = clean_param($courseparams['summary'], PARAM_TEXT); - } - - if (array_key_exists('format', $courseparams)) { - $course->format = clean_param($courseparams['format'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('startdate', $courseparams)) { - $course->startdate = clean_param($courseparams['startdate'], PARAM_INT); - } - - - if (array_key_exists('sortorder', $courseparams)) { - $course->sortorder = clean_param($courseparams['sortorder'], PARAM_INT); - } - - if (array_key_exists('showgrades', $courseparams)) { - $course->showgrades = clean_param($courseparams['showgrades'], PARAM_INT); - } - - if (array_key_exists('modinfo', $courseparams)) { - $course->modinfo = clean_param($courseparams['modinfo'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('newsitems', $courseparams)) { - $course->newsitems = clean_param($courseparams['newsitems'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('guest', $courseparams)) { - $course->guest = clean_param($courseparams['guest'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('metacourse', $courseparams)) { - $course->metacourse = clean_param($courseparams['metacourse'], PARAM_INT); - } - - if (array_key_exists('password', $courseparams)) { - $course->password = clean_param($courseparams['password'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('enrolperiod', $courseparams)) { - $course->enrolperiod = clean_param($courseparams['enrolperiod'], PARAM_INT); - } - - if (array_key_exists('defaultrole', $courseparams)) { - $course->defaultrole = clean_param($courseparams['defaultrole'], PARAM_INT); - } - - if (array_key_exists('enrollable', $courseparams)) { - $course->enrollable = clean_param($courseparams['enrollable'], PARAM_INT); - } - - if (array_key_exists('numsections', $courseparams)) { - $course->numsections = clean_param($courseparams['numsections'], PARAM_INT); - } - - if (array_key_exists('expirynotify', $courseparams)) { - $course->expirynotify = clean_param($courseparams['expirynotify'], PARAM_INT); - } - - if (array_key_exists('notifystudents', $courseparams)) { - $course->notifystudents = clean_param($courseparams['notifystudents'], PARAM_INT); - } - - if (array_key_exists('expirythreshold', $courseparams)) { - $course->expirythreshold = clean_param($courseparams['expirythreshold'], PARAM_INT); - } - - if (array_key_exists('marker', $courseparams)) { - $course->marker = clean_param($courseparams['marker'], PARAM_INT); - } - - if (array_key_exists('maxbytes', $courseparams)) { - $course->maxbytes = clean_param($courseparams['maxbytes'], PARAM_INT); - } - - if (array_key_exists('showreports', $courseparams)) { - $course->showreports = clean_param($courseparams['showreports'], PARAM_INT); - } - - if (array_key_exists('visible', $courseparams)) { - $course->visible = clean_param($courseparams['visible'], PARAM_INT); - } - - if (array_key_exists('hiddensections', $courseparams)) { - $course->hiddensections = clean_param($courseparams['hiddensections'], PARAM_INT); - } - - - if (array_key_exists('groupmode', $courseparams)) { - $course->groupmode = clean_param($courseparams['groupmode'], PARAM_INT); - } - - if (array_key_exists('groupmodeforce', $courseparams)) { - $course->groupmodeforce = clean_param($courseparams['groupmodeforce'], PARAM_INT); - } - - if (array_key_exists('defaultgroupingid', $courseparams)) { - $course->defaultgroupingid = clean_param($courseparams['defaultgroupingid'], PARAM_INT); - } - - if (array_key_exists('lang', $courseparams)) { - $course->lang = clean_param($courseparams['lang'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('theme', $courseparams)) { - $course->theme = clean_param($courseparams['theme'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('cost', $courseparams)) { - $course->cost = clean_param($courseparams['cost'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('currency', $courseparams)) { - $course->currency = clean_param($courseparams['currency'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('timecreated', $courseparams)) { - $course->timecreated = clean_param($courseparams['timecreated'], PARAM_INT); - } - - if (array_key_exists('timemodified', $courseparams)) { - $course->timemodified = clean_param($courseparams['timemodified'], PARAM_INT); - } - - if (array_key_exists('requested', $courseparams)) { - $course->requested = clean_param($courseparams['requested'], PARAM_INT); - } - - if (array_key_exists('restrictmodules', $courseparams)) { - $course->restrictmodules = clean_param($courseparams['restrictmodules'], PARAM_INT); - } - - if (array_key_exists('enrolstartdate', $courseparams)) { - $course->enrolstartdate = clean_param($courseparams['enrolstartdate'], PARAM_INT); - } - - if (array_key_exists('enrolenddate', $courseparams)) { - $course->enrolenddate = clean_param($courseparams['enrolenddate'], PARAM_INT); - } - - if (array_key_exists('enrol', $courseparams)) { - $course->enrol = clean_param($courseparams['enrol'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('enablecompletion', $courseparams)) { - $course->enablecompletion = clean_param($courseparams['enablecompletion'], PARAM_INT); - } - - $courses[] = create_course($course); - - } - return $courses; - } - else { - throw new moodle_exception('wscouldnotcreateecoursenopermission'); - } - } - - /** - * Delete multiple courses - * @global object $DB - * @param array|struct $params - need to be define as struct for XMLRPC - * @subparam string $params:course->shortname - * @subparam integer $params:course->id - * @subparam string $params:course->shortname - * @subparam string $params:course->idnumber - * @return boolean result true if success - */ - static function delete_courses($params) { - global $DB,$USER; - if (has_capability('moodle/course:delete', get_context_instance(CONTEXT_SYSTEM))) { - $courses = array(); - $result = true; - foreach ($params as $param) { - $course = new stdClass(); - if (key_exists('id', $param)) { - $param['id'] = clean_param($param['id'], PARAM_INT); - if (!delete_course($param['id'], false)) { - $result = false; - } - } else if (key_exists('idnumber', $param)) { - $param['idnumber'] = clean_param($param['idnumber'], PARAM_ALPHANUM); - //it doesn't cost that much to retrieve the course here - //as it would be done into delete_course() - $course = $DB->get_record('course', array('idnumber'=>$param['idnumber'])); - if (!delete_course($course, false)) { - $result = false; - } - } else if (key_exists('shortname', $param)) { - $param['shortname'] = clean_param($param['shortname'], PARAM_ALPHANUM); - $course = $DB->get_record('course', array('shortname'=>$param['shortname'])); - if (!delete_course($course, false)) { - $result = false; - } - } - } - return $result; - } - else { - throw new moodle_exception('wscouldnotdeletecoursenopermission'); - } - } - - /** - * Update some courses information - * @global object $DB - * @param array|struct $params - need to be define as struct for XMLRPC - * @subparam integer $params:course->id - * @subparam string $params:course->idnumber - * @subparam string $params:course->shortname - * @subparam integer $params:course->category - * @subparam string $params:course->fullname - * @subparam string $params:course->summary - * @subparam string $params:course->format - * @subparam integer $params:course->startdate - * @subparam integer $params:course->sortorder - * @subparam integer $params:course->showgrades - * @subparam string $params:course->modinfo - * @subparam string $params:course->newsitems - * @subparam string $params:course->guest - * @subparam integer $params:course->metacourse - * @subparam string $params:course->password - * @subparam integer $params:course->enrolperiod - * @subparam integer $params:course->defaultrole - * @subparam integer $params:course->enrollable - * @subparam integer $params:course->numsections - * @subparam integer $params:course->expirynotify - * @subparam integer $params:course->notifystudents - * @subparam integer $params:course->expirythreshold - * @subparam integer $params:course->marker - * @subparam integer $params:course->maxbytes - * @subparam integer $params:course->showreports - * @subparam integer $params:course->visible - * @subparam integer $params:course->hiddensections - * @subparam integer $params:course->groupmode - * @subparam integer $params:course->groupmodeforce - * @subparam integer $params:course->defaultgroupingid - * @subparam string $params:course->lang - * @subparam string $params:course->theme - * @subparam string $params:course->cost - * @subparam string $params:course->currency - * @subparam integer $params:course->timecreated - * @subparam integer $params:course->timemodified - * @subparam integer $params:course->requested - * @subparam integer $params:course->restrictmodules - * @subparam integer $params:course->enrolstartdate - * @subparam integer $params:course->enrolenddate - * @subparam string $params:course->enrol - * @subparam integer $params:course->enablecompletion - * @return boolean result true if success - */ - static function update_courses($params) { - global $DB,$USER; - - if (has_capability('moodle/course:update', get_context_instance(CONTEXT_SYSTEM))) { - $courses = array(); - $result = true; - foreach ($params as $courseparams) { - - $course = new stdClass(); - - if (array_key_exists('idnumber', $courseparams)) { - $course->idnumber = clean_param($courseparams['idnumber'], PARAM_ALPHANUM); - } - - if (array_key_exists('shortname', $courseparams)) { - $course->shortname = clean_param($courseparams['shortname'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('category', $courseparams)) { - $course->category = clean_param($courseparams['category'], PARAM_INT); - } - - if (array_key_exists('fullname', $courseparams)) { - $course->fullname = clean_param($courseparams['fullname'], PARAM_TEXT); - } - - if (array_key_exists('summary', $courseparams)) { - $course->summary = clean_param($courseparams['summary'], PARAM_TEXT); - } - - if (array_key_exists('format', $courseparams)) { - $course->format = clean_param($courseparams['format'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('startdate', $courseparams)) { - $course->startdate = clean_param($courseparams['startdate'], PARAM_INT); - } - - - if (array_key_exists('sortorder', $courseparams)) { - $course->sortorder = clean_param($courseparams['sortorder'], PARAM_INT); - } - - if (array_key_exists('showgrades', $courseparams)) { - $course->showgrades = clean_param($courseparams['showgrades'], PARAM_INT); - } - - if (array_key_exists('modinfo', $courseparams)) { - $course->modinfo = clean_param($courseparams['modinfo'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('newsitems', $courseparams)) { - $course->newsitems = clean_param($courseparams['newsitems'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('guest', $courseparams)) { - $course->guest = clean_param($courseparams['guest'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('metacourse', $courseparams)) { - $course->metacourse = clean_param($courseparams['metacourse'], PARAM_INT); - } - - if (array_key_exists('password', $courseparams)) { - $course->password = clean_param($courseparams['password'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('enrolperiod', $courseparams)) { - $course->enrolperiod = clean_param($courseparams['enrolperiod'], PARAM_INT); - } - - if (array_key_exists('defaultrole', $courseparams)) { - $course->defaultrole = clean_param($courseparams['defaultrole'], PARAM_INT); - } - - if (array_key_exists('enrollable', $courseparams)) { - $course->enrollable = clean_param($courseparams['enrollable'], PARAM_INT); - } - - if (array_key_exists('numsections', $courseparams)) { - $course->numsections = clean_param($courseparams['numsections'], PARAM_INT); - } - - if (array_key_exists('expirynotify', $courseparams)) { - $course->expirynotify = clean_param($courseparams['expirynotify'], PARAM_INT); - } - - if (array_key_exists('notifystudents', $courseparams)) { - $course->notifystudents = clean_param($courseparams['notifystudents'], PARAM_INT); - } - - if (array_key_exists('expirythreshold', $courseparams)) { - $course->expirythreshold = clean_param($courseparams['expirythreshold'], PARAM_INT); - } - - if (array_key_exists('marker', $courseparams)) { - $course->marker = clean_param($courseparams['marker'], PARAM_INT); - } - - if (array_key_exists('maxbytes', $courseparams)) { - $course->maxbytes = clean_param($courseparams['maxbytes'], PARAM_INT); - } - - if (array_key_exists('showreports', $courseparams)) { - $course->showreports = clean_param($courseparams['showreports'], PARAM_INT); - } - - if (array_key_exists('visible', $courseparams)) { - $course->visible = clean_param($courseparams['visible'], PARAM_INT); - } - - if (array_key_exists('hiddensections', $courseparams)) { - $course->hiddensections = clean_param($courseparams['hiddensections'], PARAM_INT); - } - - if (array_key_exists('groupmode', $courseparams)) { - $course->groupmode = clean_param($courseparams['groupmode'], PARAM_INT); - } - - if (array_key_exists('groupmodeforce', $courseparams)) { - $course->groupmodeforce = clean_param($courseparams['groupmodeforce'], PARAM_INT); - } - - if (array_key_exists('defaultgroupingid', $courseparams)) { - $course->defaultgroupingid = clean_param($courseparams['defaultgroupingid'], PARAM_INT); - } - - if (array_key_exists('lang', $courseparams)) { - $course->lang = clean_param($courseparams['lang'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('theme', $courseparams)) { - $course->theme = clean_param($courseparams['theme'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('cost', $courseparams)) { - $course->cost = clean_param($courseparams['cost'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('currency', $courseparams)) { - $course->currency = clean_param($courseparams['currency'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('timecreated', $courseparams)) { - $course->timecreated = clean_param($courseparams['timecreated'], PARAM_INT); - } - - if (array_key_exists('timemodified', $courseparams)) { - $course->timemodified = clean_param($courseparams['timemodified'], PARAM_INT); - } - - if (array_key_exists('requested', $courseparams)) { - $course->requested = clean_param($courseparams['requested'], PARAM_INT); - } - - if (array_key_exists('restrictmodules', $courseparams)) { - $course->restrictmodules = clean_param($courseparams['restrictmodules'], PARAM_INT); - } - - if (array_key_exists('enrolstartdate', $courseparams)) { - $course->enrolstartdate = clean_param($courseparams['enrolstartdate'], PARAM_INT); - } - - if (array_key_exists('enrolenddate', $courseparams)) { - $course->enrolenddate = clean_param($courseparams['enrolenddate'], PARAM_INT); - } - - if (array_key_exists('enrol', $courseparams)) { - $course->enrol = clean_param($courseparams['enrol'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('enablecompletion', $courseparams)) { - $course->enablecompletion = clean_param($courseparams['enablecompletion'], PARAM_INT); - } - - if (array_key_exists('id', $courseparams)) { - $course->id = clean_param($courseparams['id'], PARAM_INT); - } - - if (!update_course($course)) { - $result = false; - } - - } - return $result; - } - else { - throw new moodle_exception('wscouldnotupdatecoursenopermission'); - } - - } - - /** - * Get course modules - * @global object $DB - * @param array|struct $params - need to be define as struct for XMLRPC - * @subparam string $params:course->id - * @return array $return course modules - * @subreturn string $return:id module id - * @subreturn string $return:name module name - * @subreturn string $return:type module type - */ - static function get_course_modules($params, $type=null) { - global $DB; - if (has_capability('moodle/course:participate', get_context_instance(CONTEXT_SYSTEM))) { - $modules = array(); - foreach ($params as $courseparams) { - if (array_key_exists('id', $courseparams)) { - $id = clean_param($courseparams['id'], PARAM_INT); - } - - $activities = get_array_of_activities($id); - - foreach ($activities as $activity) { - if (empty($type)) { - $module = array('id' => $activity->id, 'courseid' => $id, 'name' => $activity->name, 'type' => $activity->mod); - $modules[] = $module; - } - else if ($type=="activities") { - if ($activity->mod != "resource" && $activity->mod != "label") { - $module = array('id' => $activity->id, 'courseid' => $id, 'name' => $activity->name, 'type' => $activity->mod); - $modules[] = $module; - } - } - else if ($type=="resources") { - if ($activity->mod == "resource" || $activity->mod == "label") { - $module = array('id' => $activity->id, 'courseid' => $id, 'resource' => $activity->name, 'type' => $activity->mod); - $modules[] = $module; - } - } - } - } - return $modules; - } - else { - throw new moodle_exception('wscouldnotgetcoursemodulesnopermission'); - } - } - - /** - * Get course activities - * @global object $DB - * @param array|struct $params - need to be define as struct for XMLRPC - * @subparam string $params:course->id - * @return array $return course activities - * @subreturn string $return:id activity id - * @subreturn string $return:name activity name - * @subreturn string $return:type activity type - */ - static function get_course_activities($params) { - course_external::get_course_modules($params, "activities"); - } - - /** - * Get course resources - * @global object $DB - * @param array|struct $params - need to be define as struct for XMLRPC - * @subparam string $params:course->id - * @return array $return course resources - * @subreturn integer $return:id resource id - * @subreturn string $return:name resource name - * @subreturn string $return:type resource type - */ - static function get_course_resources($params) { - course_external::get_course_modules($params, "resources"); - } - -} - - diff --git a/course/externallib.php b/course/externallib.php index 6b8c70803b3..ec8e627811c 100644 --- a/course/externallib.php +++ b/course/externallib.php @@ -18,12 +18,14 @@ /** * External user API * - * @package moodlecore - * @subpackage webservice + * @package core + * @subpackage course * @copyright 2009 Moodle Pty Ltd (http://moodle.com) * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +defined('MOODLE_INTERNAL') || die; + require_once("$CFG->libdir/externallib.php"); class moodle_course_external extends external_api { diff --git a/course/importstudents.html b/course/importstudents.html deleted file mode 100644 index 5b8d7423098..00000000000 --- a/course/importstudents.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - -
- -
-
-

- -
- -

-
- -
- -
- - - - '."\n"; - } - ?> -
- - - diff --git a/course/importstudents.php b/course/importstudents.php deleted file mode 100644 index 434abb70f87..00000000000 --- a/course/importstudents.php +++ /dev/null @@ -1,170 +0,0 @@ -. - -/** - * Script to assign students to a meta course by selecting which courses the meta - * course comprises. This is basically a hack of student.php that uses courses instead. - * - * @copyright 1999 Martin Dougiamas http://dougiamas.com - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @package course - */ - - require_once("../config.php"); - require_once("lib.php"); - - define("MAX_COURSES_PER_PAGE", 1000); - - $id = required_param('id',PARAM_INT); // course id - $add = optional_param('add', 0, PARAM_BOOL); - $remove = optional_param('remove', 0, PARAM_BOOL); - $showall = optional_param('showall', 0, PARAM_BOOL); - $searchtext = optional_param('searchtext', '', PARAM_RAW); // search string - $previoussearch = optional_param('previoussearch', 0, PARAM_BOOL); - $previoussearch = ($searchtext != '') or ($previoussearch) ? 1:0; - - $url = new moodle_url('/course/importstudents.php', array('id'=>$id)); - if ($add !== 0) { - $url->param('add', $add); - } - if ($remove !== 0) { - $url->param('remove', $remove); - } - if ($showall !== 0) { - $url->param('showall', $showall); - } - if ($searchtext !== '') { - $url->param('searchtext', $searchtext); - } - if ($previoussearch !== 0) { - $url->param('previoussearch', $previoussearch); - } - $PAGE->set_url($url); - - $site = get_site(); - - if (!$course = $DB->get_record('course', array('id'=>$id))) { - print_error("invalidcourseid"); - } - - require_login($course->id); - $context = get_context_instance(CONTEXT_COURSE, $course->id); - require_capability('moodle/course:managemetacourse', $context); - - if (!$course->metacourse) { - redirect("$CFG->wwwroot/course/view.php?id=$course->id"); - } - - $strassigncourses = get_string('metaassigncourses'); - $stralreadycourses = get_string('metaalreadycourses'); - $strnoalreadycourses = get_string('metanoalreadycourses'); - $strpotentialcourses = get_string('metapotentialcourses'); - $strnopotentialcourses = get_string('metanopotentialcourses'); - $straddcourses = get_string('metaaddcourse'); - $strremovecourse = get_string('metaremovecourse'); - $strsearch = get_string("search"); - $strsearchresults = get_string("searchresults"); - $strcourses = get_string("courses"); - $strshowall = get_string("showall"); - - $PAGE->navbar->add($strassigncourses); - $PAGE->set_title("$course->shortname: $strassigncourses"); - $PAGE->set_heading($site->fullname); - $PAGE->set_focuscontrol("searchtext"); - echo $OUTPUT->header(); - -/// Print a help notice about the need to use this page - - echo $OUTPUT->heading(get_string('childcourses')); - - if (!$frm = data_submitted()) { - $note = get_string("importmetacoursenote"); - echo $OUTPUT->box($note); - -/// A form was submitted so process the input - - } else { - if ($add and !empty($frm->addselect) and confirm_sesskey()) { - $timestart = $timeend = 0; - foreach ($frm->addselect as $addcourse) { - $addcourse = clean_param($addcourse, PARAM_INT); - set_time_limit(180); - if (!add_to_metacourse($course->id,$addcourse)) { - print_error("cannotmetacourse"); - } - } - } else if ($remove and !empty($frm->removeselect) and confirm_sesskey()) { - foreach ($frm->removeselect as $removecourse) { - set_time_limit(180); - $removecourse = clean_param($removecourse, PARAM_INT); - if (! remove_from_metacourse($course->id,$removecourse)) { - print_error("cannotremovefrommeta"); - } - } - } else if ($showall and confirm_sesskey()) { - $searchtext = ''; - $previoussearch = 0; - } - } - - -/// Get all existing students and teachers for this course. - if(! $alreadycourses = get_courses_in_metacourse($course->id)) { - $alreadycourses = array(); - } - - $numcourses = 0; - - -/// Get search results excluding any users already in this course - if (($searchtext != '') and $previoussearch and confirm_sesskey()) { - if ($searchcourses = get_courses_search(explode(" ",$searchtext),'fullname ASC',0,99999,$numcourses)) { - foreach ($searchcourses as $tmp) { - if (array_key_exists($tmp->id,$alreadycourses)) { - unset($searchcourses[$tmp->id]); - } - if (!empty($tmp->metacourse)) { - unset($searchcourses[$tmp->id]); - } - } - if (array_key_exists($course->id,$searchcourses)) { - unset($searchcourses[$course->id]); - } - $numcourses = count($searchcourses); - } - } - -/// If no search results then get potential students for this course excluding users already in course - if (empty($searchcourses)) { - $numcourses = count_courses_notin_metacourse($course->id); - - if ($numcourses > 0 and $numcourses <= MAX_COURSES_PER_PAGE) { - $courses = get_courses_notin_metacourse($course->id); - } else { - $courses = array(); - } - } - - echo $OUTPUT->box_start(); - - include('importstudents.html'); - - echo $OUTPUT->box_end(); - - echo $OUTPUT->footer(); - - diff --git a/course/index.php b/course/index.php index 52b70de3728..7725b299e56 100644 --- a/course/index.php +++ b/course/index.php @@ -192,18 +192,19 @@ if (!empty($move) and ($moveto >= 0) and confirm_sesskey()) { } /// Hide or show a category -if ((!empty($hide) or !empty($show)) and confirm_sesskey()) { - if (!empty($hide)) { - $tempcat = $DB->get_record('course_categories', array('id'=>$hide)); - $visible = 0; - } else { - $tempcat = $DB->get_record('course_categories', array('id'=>$show)); - $visible = 1; +if ($hide and confirm_sesskey()) { + if ($tempcat = $DB->get_record('course_categories', array('id'=>$hide))) { + require_capability('moodle/category:manage', get_category_or_system_context($tempcat->parent)); + if ($tempcat->visible == 1) { + course_category_hide($tempcat); + } } - require_capability('moodle/category:manage', get_category_or_system_context($tempcat->parent)); - if ($tempcat) { - $DB->set_field('course_categories', 'visible', $visible, array('id'=>$tempcat->id)); - $DB->set_field('course', 'visible', $visible, array('category' => $tempcat->id)); +} else if ($show and confirm_sesskey()) { + if ($tempcat = $DB->get_record('course_categories', array('id'=>$show))) { + require_capability('moodle/category:manage', get_category_or_system_context($tempcat->parent)); + if ($tempcat->visible == 0) { + course_category_show($tempcat); + } } } diff --git a/course/info.php b/course/info.php index fc3fc4e0bca..9c0d32a685f 100644 --- a/course/info.php +++ b/course/info.php @@ -29,7 +29,7 @@ } $context = get_context_instance(CONTEXT_COURSE, $course->id); - if ((!course_parent_visible($course) || (! $course->visible)) && !has_capability('moodle/course:viewhiddencourses', $context)) { + if (!$course->visible and !has_capability('moodle/course:viewhiddencourses', $context)) { print_error('coursehidden', '', $CFG->wwwroot .'/'); } @@ -44,6 +44,8 @@ echo $OUTPUT->header(); echo $OUTPUT->heading(''.format_string($course->fullname) . '
(' . format_string($course->shortname) . ')'); + //TODO: add enrol info + /* if ($course->guest || $course->password) { echo $OUTPUT->box_start('generalbox icons'); if ($course->guest) { @@ -55,17 +57,17 @@ echo "
\"\"pix_url('i/key') . "\" /> $strrequireskey
"; } echo $OUTPUT->box_end(); - } + }*/ echo $OUTPUT->box_start('generalbox info'); - $course->summary = file_rewrite_pluginfile_urls($course->summary, 'pluginfile.php', $context->id, 'course_summary', $course->id); + $course->summary = file_rewrite_pluginfile_urls($course->summary, 'pluginfile.php', $context->id, 'course_summary', NULL); echo format_text($course->summary, $course->summaryformat, NULL, $course->id); - if (!empty($CFG->coursemanager)) { - $coursemanagerroles = explode(',', $CFG->coursemanager); - foreach ($coursemanagerroles as $roleid) { + if (!empty($CFG->coursecontact)) { + $coursecontactroles = explode(',', $CFG->coursecontact); + foreach ($coursecontactroles as $roleid) { $role = $DB->get_record('role', array('id'=>$roleid)); $roleid = (int) $roleid; if ($users = get_role_users($roleid, $context, true)) { @@ -84,9 +86,7 @@ } } - require_once("$CFG->dirroot/enrol/enrol.class.php"); - $enrol = enrolment_factory::factory($course->enrol); - echo $enrol->get_access_icons($course); +// TODO: print some enrol icons echo $OUTPUT->box_end(); diff --git a/course/lib.php b/course/lib.php index 6aa9819da1b..546ac6ed1b8 100644 --- a/course/lib.php +++ b/course/lib.php @@ -20,9 +20,12 @@ * * @copyright 1999 Martin Dougiamas http://dougiamas.com * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @package course + * @package core + * @subpackage course */ +defined('MOODLE_INTERNAL') || die; + require_once($CFG->libdir.'/completionlib.php'); require_once($CFG->libdir.'/filelib.php'); @@ -1915,7 +1918,7 @@ function get_course_category_tree($id = 0, $depth = 0) { list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); list($catsql, $catparams) = $DB->get_in_or_equal(array_keys($categoryids)); $sql = "SELECT - c.id,c.sortorder,c.visible,c.fullname,c.shortname,c.password,c.summary,c.guest,c.cost,c.currency,c.category + c.id,c.sortorder,c.visible,c.fullname,c.shortname,c.summary,c.category $ccselect FROM {course} c $ccjoin @@ -2004,13 +2007,8 @@ function make_categories_options() { */ function print_category_info($category, $depth, $showcourses = false) { global $CFG, $DB, $OUTPUT; - static $strallowguests, $strrequireskey, $strsummary; - if (empty($strsummary)) { - $strallowguests = get_string('allowguests'); - $strrequireskey = get_string('requireskey'); - $strsummary = get_string('summary'); - } + $strsummary = get_string('summary'); $catlinkcss = $category->visible ? '' : ' class="dimmed" '; @@ -2028,7 +2026,7 @@ function print_category_info($category, $depth, $showcourses = false) { echo "\n\n".''; - $courses = get_courses($category->id, 'c.sortorder ASC', 'c.id,c.sortorder,c.visible,c.fullname,c.shortname,c.password,c.summary,c.guest,c.cost,c.currency'); + $courses = get_courses($category->id, 'c.sortorder ASC', 'c.id,c.sortorder,c.visible,c.fullname,c.shortname,c.summary'); if ($showcourses and $coursecount) { echo ''; @@ -2061,18 +2059,7 @@ function print_category_info($category, $depth, $showcourses = false) { echo '
'; echo ''. format_string($course->fullname).''; echo ''; - if ($course->guest ) { - echo ''; - echo ''.$strallowguests.''; - } else { - echo ''; - } - if ($course->password) { - echo ''; - echo ''.$strrequireskey.''; - } else { - echo ''; - } + //TODO: add some guest, pay icons if ($course->summary) { $link = new moodle_url('/course/info.php?id='.$course->id); echo $OUTPUT->action_link($link, ''.$strsummary.'', @@ -2186,17 +2173,17 @@ function print_courses($category) { $category = array_shift($categories); $courses = get_courses_wmanagers($category->id, 'c.sortorder ASC', - array('password','summary','summaryformat','currency')); + array('summary','summaryformat')); } else { $courses = get_courses_wmanagers('all', 'c.sortorder ASC', - array('password','summary','summaryformat','currency')); + array('summary','summaryformat')); } unset($categories); } else { $courses = get_courses_wmanagers($category->id, 'c.sortorder ASC', - array('password','summary','summaryformat','currency')); + array('summary','summaryformat')); } if ($courses) { @@ -2239,7 +2226,7 @@ function print_course($course, $highlightterms = '') { $context = get_context_instance(CONTEXT_COURSE, $course->id); // Rewrite file URLs so that they are correct - $course->summary = file_rewrite_pluginfile_urls($course->summary, 'pluginfile.php', $context->id, 'course_summary', $course->id); + $course->summary = file_rewrite_pluginfile_urls($course->summary, 'pluginfile.php', $context->id, 'course_summary', NULL); $linkcss = $course->visible ? '' : ' class="dimmed" '; @@ -2251,8 +2238,8 @@ function print_course($course, $highlightterms = '') { /// first find all roles that are supposed to be displayed - if (!empty($CFG->coursemanager)) { - $managerroles = split(',', $CFG->coursemanager); + if (!empty($CFG->coursecontact)) { + $managerroles = split(',', $CFG->coursecontact); $namesarray = array(); if (isset($course->managers)) { if (count($course->managers)) { @@ -2318,9 +2305,7 @@ function print_course($course, $highlightterms = '') { } } - require_once("$CFG->dirroot/enrol/enrol.class.php"); - $enrol = enrolment_factory::factory($course->enrol); - echo $enrol->get_access_icons($course); + // TODO: print some enrol icons echo '
'; $options = NULL; @@ -2345,7 +2330,7 @@ function print_my_moodle() { print_error('nopermissions', '', '', 'See My Moodle'); } - $courses = get_my_courses($USER->id, 'visible DESC,sortorder ASC', array('summary')); + $courses = enrol_get_my_courses('summary', 'visible DESC,sortorder ASC'); $rhosts = array(); $rcourses = array(); if (!empty($CFG->mnet_dispatcher_mode) && $CFG->mnet_dispatcher_mode==='strict') { @@ -3036,15 +3021,6 @@ function course_format_name ($course,$max=100) { } } -/** - * This function will return true if the given course is a child course at all - */ -function course_in_meta ($course) { - global $DB; - return $DB->record_exists("course_meta", array("child_course"=>$course->id)); -} - - function update_restricted_mods($course, $mods) { global $DB; @@ -3082,8 +3058,8 @@ function course_allowed_module($course,$mod) { } // Admins and admin-like people who can edit everything can also add anything. - // This is a bit wierd, really. I debated taking it out but it's enshrined in help for the setting. - if (has_capability('moodle/course:update', get_context_instance(CONTEXT_SYSTEM))) { + // Originally there was a coruse:update test only, but it did not match the test in course edit form + if (has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { return true; } @@ -3201,33 +3177,92 @@ function category_delete_move($category, $newparentid, $showfeedback=true) { * sortorder in order. * * @param $courseids is an array of course ids + * @return bool success */ function move_courses($courseids, $categoryid) { global $CFG, $DB, $OUTPUT; - if (!empty($courseids) and $category = $DB->get_record('course_categories', array('id'=>$categoryid))) { - $courseids = array_reverse($courseids); - $i = 1; - - foreach ($courseids as $courseid) { - if (!$course = $DB->get_record("course", array("id"=>$courseid))) { - echo $OUTPUT->notification("Error finding course $courseid"); - } else { - $course->category = $categoryid; - $course->sortorder = $category->sortorder + MAX_COURSES_IN_CATEGORY - $i++; - - $DB->update_record('course', $course); - - $context = get_context_instance(CONTEXT_COURSE, $course->id); - $newparent = get_context_instance(CONTEXT_COURSECAT, $course->category); - context_moved($context, $newparent); - } - } - fix_course_sortorder(); + if (empty($courseids)) { + // nothing to do + return; } + + if (!$category = $DB->get_record('course_categories', array('id'=>$categoryid))) { + return false; + } + + $courseids = array_reverse($courseids); + $i = 1; + + foreach ($courseids as $courseid) { + if ($course = $DB->get_record('course', array('id'=>$courseid), 'id, category')) { + $course->category = $category->id; + $course->sortorder = $category->sortorder + MAX_COURSES_IN_CATEGORY - $i++; + if ($category->visible == 0) { + // hide the course when moving into hidden category, + // do not update the visibleold flag - we want to get to previous state if somebody unhides the category + $course->visible = 0; + } + + $DB->update_record('course', $course); + + $context = get_context_instance(CONTEXT_COURSE, $course->id); + $newparent = get_context_instance(CONTEXT_COURSECAT, $course->category); + context_moved($context, $newparent); + } + } + fix_course_sortorder(); + return true; } +/** + * Hide course category and child course and subcategories + * @param $category + * @return void + */ +function course_category_hide($category) { + global $DB; + + $category->visible = 0; + $DB->set_field('course_categories', 'visible', 0, array('id'=>$category->id)); + $DB->set_field('course_categories', 'visibleold', 0, array('id'=>$category->id)); + $DB->execute("UPDATE {course} SET visibleold = visible WHERE category = ?", array($category->id)); // store visible flag so that we can return to it if we immediately unhide + $DB->set_field('course', 'visible', 0, array('category' => $category->id)); + // get all child categories and hide too + if ($subcats = $DB->get_records_select('course_categories', "path LIKE ?", array("$category->path/%"))) { + foreach ($subcats as $cat) { + $DB->set_field('course_categories', 'visibleold', $cat->visible, array('id'=>$cat->id)); + $DB->set_field('course_categories', 'visible', 0, array('id'=>$cat->id)); + $DB->execute("UPDATE {course} SET visibleold = visible WHERE category = ?", array($cat->id)); + $DB->set_field('course', 'visible', 0, array('category' => $cat->id)); + } + } +} + +/** + * Show course category and child course and subcategories + * @param $category + * @return void + */ +function course_category_show($category) { + global $DB; + + $category->visible = 1; + $DB->set_field('course_categories', 'visible', 1, array('id'=>$category->id)); + $DB->set_field('course_categories', 'visibleold', 1, array('id'=>$category->id)); + $DB->execute("UPDATE {course} SET visible = visibleold WHERE category = ?", array($category->id)); + // get all child categories and unhide too + if ($subcats = $DB->get_records_select('course_categories', "path LIKE ?", array("$category->path/%"))) { + foreach ($subcats as $cat) { + if ($cat->visibleold) { + $DB->set_field('course_categories', 'visible', 1, array('id'=>$cat->id)); + } + $DB->execute("UPDATE {course} SET visible = visibleold WHERE category = ?", array($cat->id)); + } + } +} + /** * Efficiently moves a category - NOTE that this can have * a huge impact access-control-wise... @@ -3237,6 +3272,7 @@ function move_category($category, $newparentcat) { $context = get_context_instance(CONTEXT_COURSECAT, $category->id); + $hidecat = false; if (empty($newparentcat->id)) { $DB->set_field('course_categories', 'parent', 0, array('id'=>$category->id)); @@ -3245,6 +3281,11 @@ function move_category($category, $newparentcat) { } else { $DB->set_field('course_categories', 'parent', $newparentcat->id, array('id'=>$category->id)); $newparent = get_context_instance(CONTEXT_COURSECAT, $newparentcat->id); + + if (!$newparentcat->visible and $category->visible) { + // better hide category when moving into hidden category, teachers may unhide afterwards and the hidden children will be restored properly + $hidecat = true; + } } context_moved($context, $newparent); @@ -3254,6 +3295,10 @@ function move_category($category, $newparentcat) { // and fix the sortorders fix_course_sortorder(); + + if ($hidecat) { + course_category_hide($category); + } } /** @@ -3361,7 +3406,7 @@ function save_local_role_names($courseid, $data) { $context = get_context_instance(CONTEXT_COURSE, $courseid); foreach ($data as $fieldname => $value) { - if (!strstr($fieldname, 'role_')) { + if (strpos($fieldname, 'role_') !== 0) { continue; } list($ignored, $roleid) = explode('_', $fieldname); @@ -3385,158 +3430,181 @@ function save_local_role_names($courseid, $data) { } /** - * Create a course and either return a $course object or false + * Create a course and either return a $course object * + * Please note this functions does not verify any access control, + * the calling code is responsible for all validation (usually it is the form definition). + * + * @param array $editoroptions course description editor options * @param object $data - all the data needed for an entry in the 'course' table + * @return object new course instance */ -function create_course($data) { - global $CFG, $USER, $DB; +function create_course($data, $editoroptions = NULL) { + global $CFG, $DB; - //check the categoryid - if (!empty($data->category) && !$data->category==0) { - $category = $DB->get_record('course_categories', array('id'=>$data->category)); - if (empty($category)) { - throw new moodle_exception('noexistingcategory'); - } - } + //check the categoryid - must be given for all new courses + $category = $DB->get_record('course_categories', array('id'=>$data->category), '*', MUST_EXIST); //check if the shortname already exist - if(!empty($data->shortname)) { - $course = $DB->get_record('course', array('shortname' => $data->shortname)); - if (!empty($course)) { + if (!empty($data->shortname)) { + if ($DB->record_exists('course', array('shortname' => $data->shortname))) { throw new moodle_exception('shortnametaken'); } } //check if the id number already exist - if(!empty($data->idnumber)) { - $course = $DB->get_record('course', array('idnumber' => $data->idnumber)); - if (!empty($course)) { + if (!empty($data->idnumber)) { + if ($DB->record_exists('course', array('idnumber' => $data->idnumber))) { throw new moodle_exception('idnumbertaken'); } } - - // preprocess allowed mods - $allowedmods = empty($data->allowedmods) ? array() : $data->allowedmods; - unset($data->allowedmods); - if ($CFG->restrictmodulesfor == 'all') { - $data->restrictmodules = 1; - - // if the user is not an admin, get the default allowed modules because - // there are no modules passed by the form - if(!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - if(!$allowedmods && $CFG->defaultallowedmodules) { - $allowedmods = explode(',', $CFG->defaultallowedmodules); - } - } - } else { - $data->restrictmodules = 0; - } - - $data->timecreated = time(); + $data->timecreated = time(); + $data->timemodified = $data->timecreated; // place at beginning of any category $data->sortorder = 0; - if ($newcourseid = $DB->insert_record('course', $data)) { // Set up new course - - $course = $DB->get_record('course', array('id'=>$newcourseid)); - - // Setup the blocks - blocks_add_default_course_blocks($course); - - update_restricted_mods($course, $allowedmods); - - $section = new object(); - $section->course = $course->id; // Create a default section. - $section->section = 0; - $section->summaryformat = FORMAT_HTML; - $section->id = $DB->insert_record('course_sections', $section); - - fix_course_sortorder(); - - add_to_log(SITEID, 'course', 'new', 'view.php?id='.$course->id, $data->fullname.' (ID '.$course->id.')'); - - // Save any custom role names. - save_local_role_names($course->id, $data); - - // Trigger events - events_trigger('course_created', $course); - - return $course; + if ($editoroptions) { + // summary text is updated later, we need context to store the files first + $data->summary = ''; + $data->summary_format = FORMAT_HTML; } - return false; // error + // init visible flags + if (isset($data->visible)) { + $data->visibleold = $data->visible; + } else { + $data->visibleold = $data->visible = 1; + } + + $newcourseid = $DB->insert_record('course', $data); + $context = get_context_instance(CONTEXT_COURSE, $newcourseid, MUST_EXIST); + + if ($editoroptions) { + // Save the files used in the summary editor and store + $data = file_postupdate_standard_editor($data, 'summary', $editoroptions, $context, 'course_summary', 0); + $DB->set_field('course', 'summary', $data->summary, array('id'=>$newcourseid)); + $DB->set_field('course', 'summaryformat', $data->summary_format, array('id'=>$newcourseid)); + } + + $course = $DB->get_record('course', array('id'=>$newcourseid)); + + // Setup the blocks + blocks_add_default_course_blocks($course); + + $section = new object(); + $section->course = $course->id; // Create a default section. + $section->section = 0; + $section->summaryformat = FORMAT_HTML; + $DB->insert_record('course_sections', $section); + + fix_course_sortorder(); + + // update module restrictions + if ($course->restrictmodules) { + if (isset($data->allowedmods)) { + update_restricted_mods($course, $allowedmods); + } else { + if (!empty($CFG->defaultallowedmodules)) { + update_restricted_mods($course, explode(',', $CFG->defaultallowedmodules)); + } + } + } + + // new context created - better mark it as dirty + mark_context_dirty($context->path); + + // Save any custom role names. + save_local_role_names($course->id, $data); + + // set up enrolments + enrol_course_updated(true, $course, $data); + + add_to_log(SITEID, 'course', 'new', 'view.php?id='.$course->id, $data->fullname.' (ID '.$course->id.')'); + + // Trigger events + events_trigger('course_created', $course); + + return $course; } /** - * Update a course and return true or false + * Update a course. + * + * Please note this functions does not verify any access control, + * the calling code is responsible for all validation (usually it is the form definition). * * @param object $data - all the data needed for an entry in the 'course' table + * @param array $editoroptions course description editor options + * @return void */ -function update_course($data) { - global $USER, $CFG, $DB; +function update_course($data, $editoroptions = NULL) { + global $CFG, $DB; - // Preprocess allowed mods - $allowedmods = empty($data->allowedmods) ? array() : $data->allowedmods; - unset($data->allowedmods); + $data->timemodified = time(); - // Normal teachers can't change setting - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - unset($data->restrictmodules); + $oldcourse = $DB->get_record('course', array('id'=>$data->id), '*', MUST_EXIST); + $context = get_context_instance(CONTEXT_COURSE, $oldcourse->id); + + if ($editoroptions) { + $data = file_postupdate_standard_editor($data, 'summary', $editoroptions, $context, 'course_summary', 0); } - $movecat = false; - $oldcourse = $DB->get_record('course', array('id'=>$data->id)); // should not fail, already tested above - // check that course id exist - if (empty($oldcourse)) { - throw new moodle_exception('courseidnotfound'); - } - - if (!has_capability('moodle/course:create', get_context_instance(CONTEXT_COURSECAT, $oldcourse->category)) - or !has_capability('moodle/course:create', get_context_instance(CONTEXT_COURSECAT, $data->category))) { - // can not move to new category, keep the old one + if (!isset($data->category) or empty($data->category)) { + // prevent nulls and 0 in category field unset($data->category); + } + $movecat = (isset($data->category) and $oldcourse->category != $data->category); - } elseif ($oldcourse->category != $data->category) { - $movecat = true; + // init visible flags + if (isset($data->visible)) { + $data->visible = $oldcourse->visible; + } + + if ($data->visible != $oldcourse->visible) { + // reset the visibleold flag when manually hiding/unhiding course + $data->visibleold = $data->visible; + } else { + if ($movecat) { + $newcategory = $DB->get_record('course_categories', array('id'=>$data->category)); + if (empty($newcategory->visible)) { + // make sure when moving into hidden category the course is hidden automatically + $data->visible = 0; + } + } } // Update with the new data - if ($DB->update_record('course', $data)) { + $DB->update_record('course', $data); - $course = $DB->get_record('course', array('id'=>$data->id)); - - add_to_log($course->id, "course", "update", "edit.php?id=$course->id", $course->id); - - // "Admins" can change allowed mods for a course - if (has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - update_restricted_mods($course, $allowedmods); - } - - if ($movecat) { - $context = get_context_instance(CONTEXT_COURSE, $course->id); - $newparent = get_context_instance(CONTEXT_COURSECAT, $course->category); - context_moved($context, $newparent); - } - - fix_course_sortorder(); - - // Test for and remove blocks which aren't appropriate anymore - blocks_remove_inappropriate($course); - - // Save any custom role names. - save_local_role_names($course->id, $data); - - // Trigger events - events_trigger('course_updated', $course); - - return true; + $course = $DB->get_record('course', array('id'=>$data->id)); + if ($movecat) { + $newparent = get_context_instance(CONTEXT_COURSECAT, $course->category); + context_moved($context, $newparent); } - return false; + fix_course_sortorder(); + + // Test for and remove blocks which aren't appropriate anymore + blocks_remove_inappropriate($course); + + // update module restrictions + if (isset($data->allowedmods)) { + update_restricted_mods($course, $allowedmods); + } + + // Save any custom role names. + save_local_role_names($course->id, $data); + + // update enrol settings + enrol_course_updated(false, $course, $data); + + add_to_log($course->id, "course", "update", "edit.php?id=$course->id", $course->id); + + // Trigger events + events_trigger('course_updated', $course); } /** @@ -3575,7 +3643,6 @@ function average_number_of_courses_modules() { * @property-read int $summarytrust * @property-read string $reason * @property-read int $requester - * @property-read string $password */ class course_request { @@ -3845,26 +3912,22 @@ class course_request { $course->showgrades = $courseconfig->showgrades; $course->showreports = $courseconfig->showreports; $course->maxbytes = $courseconfig->maxbytes; - $course->enrol = $courseconfig->enrol; - $course->enrollable = $courseconfig->enrollable; - $course->enrolperiod = $courseconfig->enrolperiod; - $course->expirynotify = $courseconfig->expirynotify; - $course->notifystudents = $courseconfig->notifystudents; - $course->expirythreshold = $courseconfig->expirythreshold; $course->groupmode = $courseconfig->groupmode; $course->groupmodeforce = $courseconfig->groupmodeforce; $course->visible = $courseconfig->visible; - $course->enrolpassword = $courseconfig->enrolpassword; - $course->guest = $courseconfig->guest; + $course->visibleold = $course->visible; $course->lang = $courseconfig->lang; + //TODO: use standard course creation function !! + // Insert the record $course->id = $DB->insert_record('course', $course); if ($course->id) { $course = $DB->get_record('course', array('id' => $course->id)); blocks_add_default_course_blocks($course); $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); - role_assign($CFG->creatornewroleid, $this->properties->requester, 0, $coursecontext->id); // assing teacher role + // TODO: do some real enrolment here + role_assign($CFG->creatornewroleid, $this->properties->requester, $coursecontext->id); // assing teacher role if (!empty($CFG->restrictmodulesfor) && $CFG->restrictmodulesfor != 'none' && !empty($CFG->restrictbydefault)) { // if we're all or requested we're ok. $allowedmods = explode(',',$CFG->defaultallowedmodules); @@ -3929,7 +3992,7 @@ class course_request { foreach ($files as $file) { $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); if (!$file->is_directory()) { - $filerecord = array('contextid'=>$coursecontext->id, 'filearea'=>'course_summary', 'itemid'=>$course->id, 'filepath'=>$file->get_filepath(), 'filename'=>$file->get_filename()); + $filerecord = array('contextid'=>$coursecontext->id, 'filearea'=>'course_summary', 'itemid'=>0, 'filepath'=>$file->get_filepath(), 'filename'=>$file->get_filename()); $fs->create_file_from_storedfile($filerecord, $file); } } diff --git a/course/pending.php b/course/pending.php index 54d502e8714..c2b92c4b0ea 100644 --- a/course/pending.php +++ b/course/pending.php @@ -115,12 +115,7 @@ if (empty($pending)) { $course->check_shortname_collision(); $row = array(); - // Show an enrolment key icon in the first column if applicable. - if (!empty($course->password)) { - $row[] = $keyicon; - } else { - $row[] = ''; - } + // TODO: Show an enrolment key icon in the first column if applicable. // Info in the other columns. $row[] = format_string($course->shortname); $row[] = format_string($course->fullname); diff --git a/course/renderer.php b/course/renderer.php index e23a9a65a28..eba9bc2f25e 100644 --- a/course/renderer.php +++ b/course/renderer.php @@ -80,7 +80,7 @@ class core_course_renderer extends plugin_renderer_base { $content .= html_writer::tag('div', get_string('expandall'), array('class'=>'removefromall collapseall')); $content .= html_writer::end_tag('div'); $content .= html_writer::end_tag('div'); - + // Return the course category tree HTML return $content; } @@ -128,18 +128,10 @@ class core_course_renderer extends plugin_renderer_base { $content .= html_writer::link(new moodle_url('/course/view.php', array('id'=>$course->id)), $course->fullname, array('class'=>'course_link')); $content .= html_writer::start_tag('div', array('class'=>'course_info clearfix')); - if ($course->guest ) { - $image = html_writer::empty_tag('img', array('src'=>$this->output->pix_url('i/guest'), 'alt'=>$this->strings->allowguests, 'title'=>$this->strings->allowguests)); - $content .= html_writer::tag('div', $image, array('class'=>'course_info_spacer')); - } else { - $content .= html_writer::tag('div', '', array('class'=>'course_info_spacer')); - } - if ($course->password) { - $image = html_writer::empty_tag('img', array('src'=>$this->output->pix_url('i/key'), 'alt'=>$this->strings->requireskey, 'title'=>$this->strings->requireskey)); - $content .= html_writer::tag('div', $image, array('class'=>'course_info_spacer')); - } else { - $content .= html_writer::tag('div', '', array('class'=>'course_info_spacer')); - } + //TODO: add enrol info + $content .= html_writer::tag('div', '', array('class'=>'course_info_spacer')); + $content .= html_writer::tag('div', '', array('class'=>'course_info_spacer')); + if ($course->summary) { $image = html_writer::empty_tag('img', array('src'=>$this->output->pix_url('i/info'), 'alt'=>$this->strings->summary)); $content .= html_writer::link(new moodle_url('/course/info.php', array('id'=>$course->id)), $image, array('title'=>$this->strings->summary)); diff --git a/course/report/completion/lib.php b/course/report/completion/lib.php index 3ca42ba701a..9b2d12271e5 100644 --- a/course/report/completion/lib.php +++ b/course/report/completion/lib.php @@ -35,6 +35,8 @@ function completion_report_extend_navigation($navigation, $course, $context) { global $CFG, $OUTPUT; if (has_capability('coursereport/completion:view', $context)) { + require_once($CFG->libdir.'/completionlib.php'); + $url = new moodle_url('/course/report/completion/index.php', array('course'=>$course->id)); $navigation->add(get_string('pluginname','coursereport_completion'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', '')); } diff --git a/course/report/log/lib.php b/course/report/log/lib.php index 7d1c92040e2..3a7b6bc7a0f 100644 --- a/course/report/log/lib.php +++ b/course/report/log/lib.php @@ -88,7 +88,7 @@ function print_mnet_log_selector_form($hostid, $course, $selecteduser=0, $select // If looking at a different host, we're interested in all our site users if ($hostid == $CFG->mnet_localhost_id && $course->id != SITEID) { - $courseusers = get_users_by_capability($context, 'moodle/course:participate', 'u.id, u.firstname, u.lastname, u.idnumber', 'lastname ASC, firstname ASC', $limitfrom, $limitnum, $selectedgroup,'', false); + $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, u.firstname, u.lastname, u.idnumber', 'lastname ASC, firstname ASC', $limitfrom, $limitnum); } else { // this may be a lot of users :-( $courseusers = $DB->get_records('user', array('deleted'=>0), 'lastaccess DESC', 'id, firstname, lastname, idnumber', $limitfrom, $limitnum); @@ -356,12 +356,7 @@ function print_log_selector_form($course, $selecteduser=0, $selecteddate='today' // Get all the possible users $users = array(); - if ($course->id != SITEID) { - $courseusers = get_users_by_capability($context, 'moodle/course:participate', 'u.id, u.firstname, u.lastname, u.idnumber', 'lastname ASC, firstname ASC', '','',$selectedgroup,null, false); - } else { - // this may be a lot of users :-( - $courseusers = $DB->get_records('user', array('deleted'=>0), 'lastaccess DESC', 'id, firstname, lastname, idnumber'); - } + $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, u.firstname, u.lastname, u.idnumber', 'lastname ASC, firstname ASC'); if (count($courseusers) < COURSE_MAX_USERS_PER_DROPDOWN && !$showusers) { $showusers = 1; diff --git a/course/request_form.php b/course/request_form.php index ed91bd02e20..d7657b7f018 100644 --- a/course/request_form.php +++ b/course/request_form.php @@ -72,11 +72,6 @@ class course_request_form extends moodleform { $mform->addHelpButton('summary_editor', 'coursesummary'); $mform->setType('summary_editor', PARAM_RAW); - $mform->addElement('passwordunmask', 'password', get_string('enrolmentkey'), 'size="25"'); - $mform->setHelpButton('password', array('enrolmentkey', get_string('enrolmentkey')), true); - $mform->setDefault('password', ''); - $mform->setType('password', PARAM_RAW); - $mform->addElement('header','requestreason', get_string('courserequestreason')); $mform->addElement('textarea', 'reason', get_string('courserequestsupport'), array('rows'=>'15', 'cols'=>'50')); diff --git a/course/reset_form.php b/course/reset_form.php index 20e5f546b88..773bbf1cb85 100644 --- a/course/reset_form.php +++ b/course/reset_form.php @@ -25,7 +25,7 @@ class course_reset_form extends moodleform { $mform->addElement('header', 'rolesheader', get_string('roles')); $roles = get_assignable_roles(get_context_instance(CONTEXT_COURSE, $COURSE->id)); - $mform->addElement('select', 'reset_roles', get_string('unenrolroleusers'), $roles, array('multiple' => 'multiple')); + $mform->addElement('select', 'unenrol_users', get_string('unenrolroleusers', 'enrol'), $roles, array('multiple' => 'multiple')); $mform->addElement('checkbox', 'reset_roles_overrides', get_string('deletecourseoverrides', 'role')); $mform->setAdvanced('reset_roles_overrides'); $mform->addElement('checkbox', 'reset_roles_local', get_string('deletelocalroles', 'role')); @@ -102,12 +102,6 @@ class course_reset_form extends moodleform { $defaults = array ('reset_events'=>1, 'reset_logs'=>1, 'reset_roles_local'=>1, 'reset_gradebook_grades'=>1, 'reset_notes'=>1); - if (!empty($COURSE->defaultrole)) { - $defaults['reset_roles'] = array($COURSE->defaultrole); - } else { - $defaults['reset_roles'] = array($CFG->defaultcourseroleid); - } - if ($allmods = $DB->get_records('modules') ) { foreach ($allmods as $mod) { $modname = $mod->name; diff --git a/course/unenrol.php b/course/unenrol.php deleted file mode 100644 index 97cde2d569f..00000000000 --- a/course/unenrol.php +++ /dev/null @@ -1,123 +0,0 @@ -. - -/** - * Remove oneself or someone else from a course, unassigning all roles one might have - * - * This will not delete any of their data from the course, but will remove them - * from the participant list and prevent any course email being sent to them. - * - * @copyright 1999 Martin Dougiamas http://dougiamas.com - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @package course - */ - -require_once("../config.php"); -require_once("lib.php"); - -$id = required_param('id', PARAM_INT); //course -$userid = optional_param('user', 0, PARAM_INT); //course -$confirm = optional_param('confirm', 0, PARAM_BOOL); - -$PAGE->set_url('/course/unenrol.php', array('id'=>$id)); - -if($userid == $USER->id){ - // the rest of this code assumes $userid=0 means - // you are unassigning yourself, so set this for the - // correct capabiliy checks & language later - $userid = 0; -} - -if (!$course = $DB->get_record('course', array('id'=>$id))) { - print_error('invalidcourseid'); -} - -if (! $context = get_context_instance(CONTEXT_COURSE, $course->id)) { - print_error('invalidcontext'); -} - -require_login($course->id); - -if ($course->metacourse) { - print_error('cantunenrollfrommetacourse', '', $CFG->wwwroot.'/course/view.php?id='.$course->id); -} - -if ($userid) { // Unenrolling someone else - require_capability('moodle/role:assign', $context, NULL, false); - - $roles = get_user_roles($context, $userid, false); - - // verify user may unassign all roles at course context - foreach($roles as $role) { - if (!user_can_assign($context, $role->roleid)) { - print_error('cannotunassignrolefrom', '', '', - $role->roleid); - } - } - -} else { // Unenrol yourself - require_capability('moodle/role:unassignself', $context, NULL, false); -} - -if (!empty($USER->access['rsw'][$context->path])) { - print_error('cantunenrollinthisrole', '', - $CFG->wwwroot.'/course/view.php?id='.$course->id); -} - -if ($confirm and confirm_sesskey()) { - if ($userid) { - if (! role_unassign(0, $userid, 0, $context->id)) { - print_error("unenrolerror"); - } - - add_to_log($course->id, 'course', 'unenrol', - "view.php?id=$course->id", $course->id); - redirect($CFG->wwwroot.'/user/index.php?id='.$course->id); - - } else { - if (! role_unassign(0, $USER->id, 0, $context->id)) { - print_error("unenrolerror"); - } - - // force a refresh of mycourses - unset($USER->mycourses); - add_to_log($course->id, 'course', 'unenrol', - "view.php?id=$course->id", $course->id); - - redirect($CFG->wwwroot); - } -} - - -$strunenrol = get_string('unenrol'); -$PAGE->navbar->add($strunenrol); -$PAGE->set_title("$course->shortname: $strunenrol"); -$PAGE->set_heading($course->fullname); -echo $OUTPUT->header(); -if ($userid) { - if (!$user = $DB->get_record('user', array('id'=>$userid))) { - print_error('nousers'); - } - $strunenrolsure = get_string('unenrolsure', '', fullname($user, true)); - echo $OUTPUT->confirm($strunenrolsure, "unenrol.php?id=$id&user=$user->id&confirm=yes", $PAGE->url); -} else { - $strunenrolsure = get_string('unenrolsure', '', get_string("yourself")); - echo $OUTPUT->confirm($strunenrolsure, "unenrol.php?id=$id&confirm=yes", $PAGE->url); -} - -echo $OUTPUT->footer(); - diff --git a/course/user.php b/course/user.php index c29f089237a..23a0ce71e79 100644 --- a/course/user.php +++ b/course/user.php @@ -53,8 +53,9 @@ require_login(); $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); $personalcontext = get_context_instance(CONTEXT_USER, $user->id); +require_login(); $PAGE->set_pagelayout('admin'); -if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext) and !has_capability('moodle/course:participate', $coursecontext)) { +if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext) and !is_enrolled($coursecontext)) { // do not require parents to be enrolled in courses ;-) $PAGE->set_course($course); } else { diff --git a/enrol/authorize/db/upgrade.php b/enrol/authorize/db/upgrade.php index 424a71bc6ba..d63a5d747ab 100644 --- a/enrol/authorize/db/upgrade.php +++ b/enrol/authorize/db/upgrade.php @@ -28,7 +28,7 @@ function xmldb_enrol_authorize_upgrade($oldversion) { //===== 1.9.0 upgrade line ======// - if ($result && $oldversion < 2008020500 && is_enabled_enrol('authorize')) { + if ($result && $oldversion < 2008020500 && enrol_is_enabled('authorize')) { require_once($CFG->dirroot.'/enrol/authorize/localfuncs.php'); if (!check_curl_available()) { echo $OUTPUT->notification("You are using the authorize.net enrolment plugin for payment handling but cUrl is not available. diff --git a/enrol/authorize/enrol.php b/enrol/authorize/enrol.php index bc7816111bc..c342baba27a 100755 --- a/enrol/authorize/enrol.php +++ b/enrol/authorize/enrol.php @@ -1,6 +1,5 @@ dirroot.'/enrol/enrol.class.php'); require_once($CFG->dirroot.'/enrol/authorize/const.php'); require_once($CFG->dirroot.'/enrol/authorize/localfuncs.php'); require_once($CFG->dirroot.'/enrol/authorize/authorizenet.class.php'); @@ -49,7 +48,7 @@ class enrolment_plugin_authorize print_error('httpsrequired', 'enrol_authorize'); } else { $wwwsroot = str_replace('http:','https:', $CFG->wwwroot); - redirect("$wwwsroot/course/enrol.php?id=$course->id"); + redirect("$wwwsroot/enrol/index.php?id=$course->id"); exit; } } @@ -685,7 +684,8 @@ class enrolment_plugin_authorize $timeend = $order->settletime + $course->enrolperiod; } $user = $DB->get_record('user', array('id'=>$order->userid)); - if (role_assign($role->id, $user->id, 0, $context->id, $timestart, $timeend, 0, 'authorize')) { + // TODO: do some real enrolment here + if (role_assign($role->id, $user->id, $context->id, 'enrol_authorize')) { $this->log .= "User($user->id) has been enrolled to course($course->id).\n"; if (!empty($CFG->enrol_mailstudents)) { $sendem[] = $order->id; diff --git a/enrol/authorize/locallib.php b/enrol/authorize/locallib.php index a9620e08c6d..9e010ce19d4 100644 --- a/enrol/authorize/locallib.php +++ b/enrol/authorize/locallib.php @@ -358,7 +358,7 @@ function authorize_print_order($orderid) } else { if (!empty($unenrol)) { - role_unassign(0, $order->userid, 0, $coursecontext->id); + role_unassign_all(array('userid'=>$order->userid, 'contextid'=>$coursecontext->id, 'component'=>'enrol_authorize'), true, true); } redirect("$CFG->wwwroot/enrol/authorize/index.php?order=$orderid"); } @@ -383,7 +383,7 @@ function authorize_print_order($orderid) elseif (ORDER_DELETE == $do && in_array(ORDER_DELETE, $statusandactions->actions)) { if ($confirm && confirm_sesskey()) { if (!empty($unenrol)) { - role_unassign(0, $order->userid, 0, $coursecontext->id); + role_unassign_all(array('userid'=>$order->userid, 'contextid'=>$coursecontext->id, 'component'=>'enrol_authorize'), true, true); } $DB->delete_records('enrol_authorize', array('id'=>$orderid)); redirect("$CFG->wwwroot/enrol/authorize/index.php"); @@ -436,7 +436,7 @@ function authorize_print_order($orderid) if (AN_APPROVED == AuthorizeNet::process($suborder, $message, $extra, AN_ACTION_VOID)) { if (empty($CFG->an_test)) { if (!empty($unenrol)) { - role_unassign(0, $order->userid, 0, $coursecontext->id); + role_unassign_all(array('userid'=>$order->userid, 'contextid'=>$coursecontext->id, 'component'=>'enrol_authorize'), true, true); } redirect("$CFG->wwwroot/enrol/authorize/index.php?order=$orderid"); } diff --git a/enrol/authorize/uploadcsv.php b/enrol/authorize/uploadcsv.php index e4c90c959f4..d61df38f067 100644 --- a/enrol/authorize/uploadcsv.php +++ b/enrol/authorize/uploadcsv.php @@ -215,7 +215,8 @@ function authorize_process_csv($filename) { $timestart = time(); $timeend = $timestart + $course->enrolperiod; } - if (role_assign($role->id, $user->id, 0, $coursecontext->id, $timestart, $timeend, 0, 'authorize')) { + //TODO: do some real enrolment here + if (role_assign($role->id, $user->id, $coursecontext->id, 'enrol_authorize')) { $imported++; if (!empty($CFG->enrol_mailstudents)) { $sendem[] = $order->id; diff --git a/enrol/category/cli/sync.php b/enrol/category/cli/sync.php new file mode 100644 index 00000000000..37ce194b216 --- /dev/null +++ b/enrol/category/cli/sync.php @@ -0,0 +1,38 @@ +. + +/** + * CLI sync for full category enrol synchronisation. + * + * @package enrol_category + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +if (isset($_SERVER['REMOTE_ADDR'])) { + error_log("enrol/category/cli/sync.php can not be called from web server!"); + exit; +} + +require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php'); +require_once("$CFG->dirroot/enrol/category/locallib.php"); + +if (!enrol_is_enabled('category')) { + die('enrol_category plugin is disabled, sync is disabled'); +} + +enrol_category_sync_full(); diff --git a/enrol/category/db/access.php b/enrol/category/db/access.php new file mode 100644 index 00000000000..afe29506521 --- /dev/null +++ b/enrol/category/db/access.php @@ -0,0 +1,38 @@ +. + +/** + * Capabilities for category access plugin. + * + * @package enrol_category + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$capabilities = array( + // marks roles that have category role assignments synchronised to course enrolments + // overrides bellow system context are ignored (for performance reasons). + // by default his is not allowed in new installs, admins have to explicitly allow category enrolments + 'enrol/category:synchronised' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_SYSTEM, + 'legacy' => array( + ) + ), +); + + diff --git a/enrol/category/db/events.php b/enrol/category/db/events.php new file mode 100644 index 00000000000..9037d79fd78 --- /dev/null +++ b/enrol/category/db/events.php @@ -0,0 +1,40 @@ +. + +/** + * category enrolment plugin event handler definition. + * + * @package enrol_category + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/* List of handlers */ +$handlers = array ( + 'role_assigned' => array ( + 'handlerfile' => '/enrol/category/locallib.php', + 'handlerfunction' => array('enrol_category_handler', 'role_assigned'), + 'schedule' => 'instant' + ), + + 'role_unassigned' => array ( + 'handlerfile' => '/enrol/category/locallib.php', + 'handlerfunction' => array('enrol_category_handler', 'role_unassigned'), + 'schedule' => 'instant' + ), + +); diff --git a/enrol/category/db/install.php b/enrol/category/db/install.php new file mode 100644 index 00000000000..7299a3396de --- /dev/null +++ b/enrol/category/db/install.php @@ -0,0 +1,69 @@ +. + +/** + * category enrolment plugin installation. + * + * @package enrol_category + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +function xmldb_enrol_category_install() { + global $CFG, $DB; + + if (!$DB->record_exists_select('role_assignments', "contextid IN (SELECT id FROM {context} WHERE contextlevel = ?)", array(CONTEXT_COURSECAT))) { + // fresh install or nobody used category enrol + return; + } + + // existing sites need a way to keep category role enrols, but we do not want to encourage that on new sites + + // extremely ugly hack, the sync depends on the capabilities so we unfortunately force update of caps here + // note: this is not officially supported and should not be copied elsewhere! :-( + update_capabilities('enrol_category'); + $syscontext = get_context_instance(CONTEXT_SYSTEM); + $archetypes = array('student', 'teacher', 'editingteacher'); + $enableplugin = false; + foreach ($archetypes as $archetype) { + $roles = get_archetype_roles($archetype); + foreach ($roles as $role) { + if (!$DB->record_exists_select('role_assignments', "roleid = ? AND contextid IN (SELECT id FROM {context} WHERE contextlevel = ?)", array($role->id, CONTEXT_COURSECAT))) { + continue; + } + assign_capability('enrol/category:synchronised', CAP_ALLOW, $role->id, $syscontext->id, true); + $levels = get_role_contextlevels($role->id); + $levels[] = CONTEXT_COURSECAT; + set_role_contextlevels($role->id, $levels); + $enableplugin = true; + } + } + + if (!$enableplugin) { + return; + } + + // enable this plugin + $enabledplugins = explode(',', $CFG->enrol_plugins_enabled); + $enabledplugins[] = 'category'; + $enabledplugins = array_unique($enabledplugins); + set_config('enrol_plugins_enabled', implode(',', $enabledplugins)); + + // brute force course resync, this may take a while + require_once("$CFG->dirroot/enrol/category/locallib.php"); + enrol_category_sync_full(); +} diff --git a/enrol/category/lang/en/enrol_category.php b/enrol/category/lang/en/enrol_category.php new file mode 100644 index 00000000000..7a1344940ac --- /dev/null +++ b/enrol/category/lang/en/enrol_category.php @@ -0,0 +1,28 @@ +. + +/** + * Strings for component 'enrol_category', language 'en', branch 'MOODLE_20_STABLE' + * + * @package enrol_category + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['category:synchronised'] = 'Role assignments synchronised to course enrolment'; +$string['pluginname'] = 'Category enrolments'; +$string['pluginname_desc'] = 'Category enrolment plugin is a legacy solution for enrolments at the course category level via role assignments. It is recommended to use cohort synchronisation instead.'; diff --git a/enrol/category/lib.php b/enrol/category/lib.php new file mode 100644 index 00000000000..01f3466b919 --- /dev/null +++ b/enrol/category/lib.php @@ -0,0 +1,97 @@ +. + +/** + * Category enrolment plugin. + * + * @package enrol_category + * @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; + +/** + * category enrolment plugin implementation. + * @author Petr Skoda + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_category_plugin extends enrol_plugin { + + /** + * Is it possible to delete enrol instance via standard UI? + * + * @param object $instance + * @return bool + */ + public function instance_deleteable($instance) { + global $DB; + + if (!enrol_is_enabled('category')) { + return true; + } + // allow delete only when no synced users here + return !$DB->record_exists('user_enrolments', array('enrolid'=>$instance->id)); + } + + /** + * 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_candidate_link($courseid) { + // instances are added automatically as necessary + return NULL; + } + + /** + * Called for all enabled enrol plugins that returned true from is_cron_required(). + * @return void + */ + public function cron() { + global $CFG; + + if (!enrol_is_enabled('category')) { + return; + } + + require_once("$CFG->dirroot/enrol/category/locallib.php"); + enrol_category_sync_full(); + } + + /** + * Called after updating/inserting course. + * + * @param bool $inserted true if course just inserted + * @param object $course + * @param object $data form data + * @return void + */ + public function course_updated($inserted, $course, $data) { + global $CFG; + + if (!enrol_is_enabled('category')) { + return; + } + + // sync category enrols + require_once("$CFG->dirroot/enrol/category/locallib.php"); + enrol_category_sync_course($course); + } +} + + diff --git a/enrol/category/locallib.php b/enrol/category/locallib.php new file mode 100644 index 00000000000..815d0fa278e --- /dev/null +++ b/enrol/category/locallib.php @@ -0,0 +1,323 @@ +. + +/** + * Local stuff for category enrolment plugin. + * + * @package enrol_category + * @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; + +/** + * Event handler for category enrolment plugin. + * + * We try to keep everything in sync via listening to events, + * it may fail sometimes, so we always do a full sync in cron too. + */ +class enrol_category_handler { + public function role_assigned($ra) { + global $DB; + + if (!enrol_is_enabled('category')) { + return true; + } + + //only category level roles are interesting + $parentcontext = get_context_instance_by_id($ra->contextid); + if ($parentcontext->contextlevel != CONTEXT_COURSECAT) { + return true; + } + + // make sure the role is to be actually synchronised + // please note we are ignoring overrides of the synchronised capability (for performance reasons in full sync) + $syscontext = get_context_instance(CONTEXT_SYSTEM); + if (!$DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$ra->roleid, 'capability'=>'enrol/category:synchronised', 'permission'=>CAP_ALLOW))) { + return true; + } + + // add necessary enrol instances + $plugin = enrol_get_plugin('category'); + $sql = "SELECT c.* + FROM {course} c + JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel AND ctx.path LIKE :match) + LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'category') + WHERE e.id IS NULL"; + $params = array('courselevel'=>CONTEXT_COURSE, 'match'=>$parentcontext->path.'/%'); + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $course) { + $plugin->add_instance($course); + } + $rs->close(); + + // now look for missing enrols + $sql = "SELECT e.* + FROM {course} c + JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel AND ctx.path LIKE :match) + JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'category') + LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid) + WHERE ue.id IS NULL"; + $params = array('courselevel'=>CONTEXT_COURSE, 'match'=>$parentcontext->path.'/%', 'userid'=>$ra->userid); + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $instance) { + $plugin->enrol_user($instance, $ra->userid); + } + $rs->close(); + + return true; + } + + public function role_unassigned($ra) { + global $DB; + + if (!enrol_is_enabled('category')) { + return true; + } + + // only category level roles are interesting + $parentcontext = get_context_instance_by_id($ra->contextid); + if ($parentcontext->contextlevel != CONTEXT_COURSECAT) { + return true; + } + + // now this is going to be a bit slow, take all enrolments in child courses and verify each separately + $syscontext = get_context_instance(CONTEXT_SYSTEM); + $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext); + + $plugin = enrol_get_plugin('category'); + + $sql = "SELECT e.* + FROM {course} c + JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel AND ctx.path LIKE :match) + JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'category') + JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid)"; + $params = array('courselevel'=>CONTEXT_COURSE, 'match'=>$parentcontext->path.'/%', 'userid'=>$ra->userid); + $rs = $DB->get_recordset_sql($sql, $params); + + list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r000'); + $params['userid'] = $ra->userid; + + foreach ($rs as $instance) { + $coursecontext = get_context_instance(CONTEXT_COURSE, $instance->courseid); + $contextids = get_parent_contexts($coursecontext); + array_pop($contextids); // remove system context, we are interested in categories only + + list($contextids, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'c000'); + $params = array_merge($params, $contextparams); + + $sql = "SELECT ra.id + FROM {role_assignments} ra + WHERE ra.userid = :userid AND ra.contextid $contextids AND ra.roleid $roleids"; + if (!$DB->record_exists_sql($sql, $params)) { + // user does not have any interesting role in any parent context, let's unenrol + $plugin->unenrol_user($instance, $ra->userid); + } + } + $rs->close(); + + return true; + } +} + +/** + * Sync all category enrolments in one course + * @param int $courseid course id + * @return void + */ +function enrol_category_sync_course($course) { + global $DB; + + if (!enrol_is_enabled('category')) { + return; + } + + $plugin = enrol_get_plugin('category'); + + $syscontext = get_context_instance(CONTEXT_SYSTEM); + $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext); + + // first find out if any parent category context contains interesting role assignments + $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); + $contextids = get_parent_contexts($coursecontext); + array_pop($contextids); // remove system context, we are interested in categories only + + list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r000'); + list($contextids, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'c000'); + $params = array_merge($params, $contextparams); + $params['courseid'] = $course->id; + + $sql = "SELECT 'x' + FROM {role_assignments} + WHERE roleid $roleids AND contextid $contextids"; + if (!$DB->record_exists_sql($sql, $params)) { + if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) { + // should be max one instance, but anyway + foreach ($instances as $instance) { + $plugin->delete_instance($instance); + } + } + return; + } + + // make sure the enrol instance exists - there should be always only one instance + $delinstances = array(); + if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) { + $instance = array_shift($instances); + $delinstances = $instances; + } else { + $i = $plugin->add_instance($course); + $instance = $DB->get_record('enrol', array('id'=>$i)); + } + + // add new enrolments + $sql = "SELECT ra.userid + FROM (SELECT DISTINCT xra.userid + FROM {role_assignments} xra + WHERE xra.roleid $roleids AND xra.contextid $contextids + ) ra + LEFT JOIN {user_enrolments} ue ON (ue.enrolid = :instanceid AND ue.userid = ra.userid) + WHERE ue.id IS NULL"; + $params['instanceid'] = $instance->id; + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $ra) { + $plugin->enrol_user($instance, $ra->userid); + } + $rs->close(); + + // remove unwanted enrolments + $sql = "SELECT DISTINCT ue.userid + FROM {user_enrolments} ue + LEFT JOIN {role_assignments} ra ON (ra.roleid $roleids AND ra.contextid $contextids AND ra.userid = ue.userid) + WHERE ue.enrolid = :instanceid AND ra.id IS NULL"; + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $ra) { + $plugin->unenrol_user($instance, $ra->userid); + } + $rs->close(); + + if ($delinstances) { + // we have to do this as the last step in order to prevent temporary unenrolment + foreach ($delinstances as $delinstance) { + $plugin->delete_instance($delinstance); + } + } +} + +function enrol_category_sync_full() { + global $DB; + + + if (!enrol_is_enabled('category')) { + return; + } + + // we may need a lot of time here + @set_time_limit(0); + + $plugin = enrol_get_plugin('category'); + + $syscontext = get_context_instance(CONTEXT_SYSTEM); + + // any interesting roles worth synchronising? + if (!$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext)) { + // yay, nothing to do, so let's remove all leftovers + if ($instances = $DB->get_records('enrol', array('enrol'=>'category'))) { + $plugin->delete_instance($instance); + } + } + + list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r000'); + $params['courselevel'] = CONTEXT_COURSE; + $params['catlevel'] = CONTEXT_COURSECAT; + + // first of all add necessay enrol instances to all courses + $parentcat = $DB->sql_concat("cat.path", "'/%'"); + $sql = "SELECT DISTINCT c.* + FROM {course} c + JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel) + JOIN (SELECT DISTINCT cctx.path + FROM {course_categories} cc + JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel) + JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids) + ) cat ON (ctx.path LIKE $parentcat) + LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'category') + WHERE e.id IS NULL"; + + $rs = $DB->get_recordset_sql($sql, $params); + foreach($rs as $course) { + $plugin->add_instance($course); + } + $rs->close(); + + // now look for courses that do not have any interesting roles in parent contexts, + // but still have the instance and delete them + $sql = "SELECT e.* + FROM {enrol} e + JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel) + LEFT JOIN (SELECT DISTINCT cctx.path + FROM {course_categories} cc + JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel) + JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids) + ) cat ON (ctx.path LIKE $parentcat) + WHERE e.enrol = 'category' AND cat.path IS NULL"; + + $rs = $DB->get_recordset_sql($sql, $params); + foreach($rs as $instance) { + $plugin->delete_instance($instance); + } + $rs->close(); + + // add missing enrolments + $sql = "SELECT e.*, cat.userid + FROM {enrol} e + JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel) + JOIN (SELECT DISTINCT cctx.path, ra.userid + FROM {course_categories} cc + JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel) + JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids) + ) cat ON (ctx.path LIKE $parentcat) + LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = cat.userid) + WHERE e.enrol = 'category' AND ue.id IS NULL"; + $rs = $DB->get_recordset_sql($sql, $params); + foreach($rs as $instance) { + $userid = $instance->userid; + unset($instance->userid); + $plugin->enrol_user($instance, $userid); + } + $rs->close(); + + // remove stale enrolments + $sql = "SELECT e.*, ue.userid + FROM {enrol} e + JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel) + JOIN {user_enrolments} ue ON (ue.enrolid = e.id) + LEFT JOIN (SELECT DISTINCT cctx.path, ra.userid + FROM {course_categories} cc + JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel) + JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids) + ) cat ON (ctx.path LIKE $parentcat AND cat.userid = ue.userid) + WHERE e.enrol = 'category' AND cat.userid IS NULL"; + $rs = $DB->get_recordset_sql($sql, $params); + foreach($rs as $instance) { + $userid = $instance->userid; + unset($instance->userid); + $plugin->unenrol_user($instance, $userid); + } + $rs->close(); +} diff --git a/enrol/category/settings.php b/enrol/category/settings.php new file mode 100644 index 00000000000..653fe1f1fb7 --- /dev/null +++ b/enrol/category/settings.php @@ -0,0 +1,37 @@ +. + +/** + * category enrolment plugin settings and presets. + * + * @package enrol_category + * @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_category_settings', '', get_string('pluginname_desc', 'enrol_category'))); + + + //--- enrol instance defaults ---------------------------------------------------------------------------- + +} + diff --git a/enrol/category/version.php b/enrol/category/version.php new file mode 100644 index 00000000000..e14f1bfae4f --- /dev/null +++ b/enrol/category/version.php @@ -0,0 +1,27 @@ +. + +/** + * Category enrolment plugin version specification. + * + * @package enrol_category + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$plugin->version = 2010061500; +$plugin->cron = 60; \ No newline at end of file diff --git a/enrol/cohort/addinstance.php b/enrol/cohort/addinstance.php new file mode 100644 index 00000000000..77fcc45a742 --- /dev/null +++ b/enrol/cohort/addinstance.php @@ -0,0 +1,60 @@ +. + +/** + * Adds new instance of enrol_cohort to specified course. + * + * @package enrol_cohort + * @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("$CFG->dirroot/enrol/cohort/addinstance_form.php"); +require_once("$CFG->dirroot/enrol/cohort/locallib.php"); + +$id = required_param('id', PARAM_INT); // course id + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +require_login($course); +require_capability('moodle/course:enrolconfig', $context); + +$enrol = enrol_get_plugin('cohort'); +if (!$enrol->get_candidate_link($course->id)) { + redirect(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); +} + +$mform = new enrol_cohort_addinstance_form(NULL, $course); + +if ($mform->is_cancelled()) { + redirect(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); + +} else if ($data = $mform->get_data()) { + $enrol->add_instance($course, array('customint1'=>$data->cohortid, 'roleid'=>$data->roleid)); + enrol_cohort_sync($course->id); + redirect(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); +} + +$PAGE->set_url('/enrol/cohort/addinstance.php', array('id'=>$course->id)); + +echo $OUTPUT->header(); + +$mform->display(); + +echo $OUTPUT->footer(); diff --git a/enrol/cohort/addinstance_form.php b/enrol/cohort/addinstance_form.php new file mode 100644 index 00000000000..b7b2a933cc9 --- /dev/null +++ b/enrol/cohort/addinstance_form.php @@ -0,0 +1,72 @@ +. + +/** + * Adds instance form + * + * @package enrol_cohort + * @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_cohort_addinstance_form extends moodleform { + function definition() { + global $CFG, $DB; + + $mform = $this->_form; + $course = $this->_customdata; + $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); + + $enrol = enrol_get_plugin('cohort'); + + //TODO: add only cohorts from parent contexts of this course + $cohorts = array('' => get_string('choosedots')); + $rs = $DB->get_recordset('cohort', array(), 'name ASC', 'id, name, contextid'); + foreach ($rs as $c) { + $context = get_context_instance_by_id($c->contextid); + if (!has_capability('moodle/cohort:view', $context)) { + continue; + } + $cohorts[$c->id] = format_string($c->name); + } + $rs->close(); + + $roles = get_assignable_roles($coursecontext); + + $mform->addElement('header','general', get_string('pluginname', 'enrol_cohort')); + + $mform->addElement('select', 'cohortid', get_string('cohort', 'cohort'), $cohorts); + $mform->addRule('cohortid', get_string('required'), 'required', null, 'client'); + + $mform->addElement('select', 'roleid', get_string('role'), $roles); + $mform->addRule('roleid', get_string('required'), 'required', null, 'client'); + $mform->setDefault('roleid', $enrol->get_config('roleid')); + + $mform->addElement('hidden', 'id', null); + $mform->setType('id', PARAM_INT); + + $this->add_action_buttons(); + + $this->set_data(array('id'=>$course->id)); + } + + //TODO: validate duplicate role-cohort does not exist +} diff --git a/enrol/cohort/db/access.php b/enrol/cohort/db/access.php new file mode 100644 index 00000000000..c43116ba908 --- /dev/null +++ b/enrol/cohort/db/access.php @@ -0,0 +1,37 @@ +. + +/** + * Capabilities for cohort access plugin. + * + * @package enrol_cohort + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$capabilities = array( + // configure the cohort plugin settings in each course + 'enrol/cohort:config' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'manager' => CAP_ALLOW, + ) + ), +); + + diff --git a/enrol/cohort/db/events.php b/enrol/cohort/db/events.php new file mode 100644 index 00000000000..c4768281a52 --- /dev/null +++ b/enrol/cohort/db/events.php @@ -0,0 +1,45 @@ +. + +/** + * Cohort enrolment plugin event handler definition. + * + * @package enrol_cohort + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/* List of handlers */ +$handlers = array ( + 'cohort_member_added' => array ( + 'handlerfile' => '/enrol/cohort/locallib.php', + 'handlerfunction' => array('enrol_cohort_handler', 'member_added'), + 'schedule' => 'instant' + ), + + 'cohort_member_removed' => array ( + 'handlerfile' => '/enrol/cohort/locallib.php', + 'handlerfunction' => array('enrol_cohort_handler', 'member_removed'), + 'schedule' => 'instant' + ), + + 'cohort_deleted' => array ( + 'handlerfile' => '/enrol/cohort/locallib.php', + 'handlerfunction' => array('enrol_cohort_handler', 'deleted'), + 'schedule' => 'instant' + ), +); diff --git a/enrol/cohort/lang/en/enrol_cohort.php b/enrol/cohort/lang/en/enrol_cohort.php new file mode 100644 index 00000000000..d5fa00647df --- /dev/null +++ b/enrol/cohort/lang/en/enrol_cohort.php @@ -0,0 +1,28 @@ +. + +/** + * Strings for component 'enrol_cohort', language 'en', branch 'MOODLE_20_STABLE' + * + * @package enrol_cohort + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['cohort:config'] = 'Configure cohort instances'; +$string['pluginname'] = 'Cohort sync'; +$string['pluginname_desc'] = 'Cohort enrolment plugin synchronises cohort members with course participants.'; diff --git a/enrol/cohort/lib.php b/enrol/cohort/lib.php new file mode 100644 index 00000000000..cb4836c85b1 --- /dev/null +++ b/enrol/cohort/lib.php @@ -0,0 +1,118 @@ +. + +/** + * Cohort enrolment plugin. + * + * @package enrol_cohort + * @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; + +/** + * Cohort enrolment plugin implementation. + * @author Petr Skoda + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_cohort_plugin extends enrol_plugin { + /** + * Returns localised name of enrol instance + * + * @param object $instance (null is accepted too) + * @return string + */ + public function get_instance_name($instance) { + global $DB; + + if (empty($instance)) { + $enrol = $this->get_name(); + return get_string('pluginname', 'enrol_'.$enrol); + } else if (empty($instance->name)) { + $enrol = $this->get_name(); + if ($role = $DB->get_record('role', array('id'=>$instance->roleid))) { + $role = role_get_name($role, get_context_instance(CONTEXT_COURSE, $instance->courseid)); + } else { + $role = get_string('error'); + } + + return get_string('pluginname', 'enrol_'.$enrol) . ' (' . format_string($DB->get_field('cohort', 'name', array('id'=>$instance->customint1))) . ' - ' . $role .')'; + } else { + return format_string($instance->name); + } + } + + /** + * 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_candidate_link($courseid) { + global $DB; + + if (!has_capability('moodle/course:enrolconfig', get_context_instance(CONTEXT_COURSE, $courseid, MUST_EXIST))) { + return NULL; + } + if (!$DB->record_exists('cohort', array())) { + //TODO: consider only parent contexts + return NULL; + } + // multiple instances supported - multiple parent courses linked + return new moodle_url('/enrol/cohort/addinstance.php', array('id'=>$courseid)); + } + + /** + * Called for all enabled enrol plugins that returned true from is_cron_required(). + * @return void + */ + public function cron() { + global $CFG; + + // purge all roles if cohort sync disabled, those can be recreated later here in cron + if (!enrol_is_enabled('cohort')) { + role_unassign_all(array('component'=>'cohort_enrol')); + return; + } + + require_once("$CFG->dirroot/enrol/cohort/locallib.php"); + enrol_cohort_sync(); + } + + /** + * Called after updating/inserting course. + * + * @param bool $inserted true if course just inserted + * @param object $course + * @param object $data form data + * @return void + */ + public function course_updated($inserted, $course, $data) { + global $CFG; + + if (!$inserted) { + // sync cohort enrols + require_once("$CFG->dirroot/enrol/cohort/locallib.php"); + enrol_cohort_sync($course->id); + } else { + // cohorts are never inserted automatically + } + + } +} + + diff --git a/enrol/cohort/locallib.php b/enrol/cohort/locallib.php new file mode 100644 index 00000000000..b71872d24b2 --- /dev/null +++ b/enrol/cohort/locallib.php @@ -0,0 +1,189 @@ +. + +/** + * Local stuff for cohort enrolment plugin. + * + * @package enrol_cohort + * @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; + +/** + * Event handler for cohort enrolment plugin. + * + * We try to keep everything in sync via listening to events, + * it may fail sometimes, so we always do a full sync in cron too. + */ +class enrol_cohort_handler { + public function member_added($ca) { + global $DB; + + if (!enrol_is_enabled('cohort')) { + return true; + } + + // does anything want to sync with this parent? + //TODO: add join to role table to make sure that roleid actually exists + if (!$enrols = $DB->get_records('enrol', array('customint1'=>$ca->cohortid, 'enrol'=>'cohort'), 'id ASC')) { + return true; + } + + $plugin = enrol_get_plugin('cohort'); + foreach ($enrols as $enrol) { + // no problem if already enrolled + $plugin->enrol_user($enrol, $ca->userid, $enrol->roleid); + } + + return true; + } + + public function member_removed($ca) { + global $DB; + + // does anything want to sync with this parent? + if (!$enrols = $DB->get_records('enrol', array('customint1'=>$ca->cohortid, 'enrol'=>'cohort'), 'id ASC')) { + return true; + } + + $plugin = enrol_get_plugin('cohort'); + foreach ($enrols as $enrol) { + // no problem if already enrolled + $plugin->unenrol_user($enrol, $ca->userid); + } + + return true; + } + + public function deleted($cohort) { + global $DB; + + // does anything want to sync with this parent? + if (!$enrols = $DB->get_records('enrol', array('customint1'=>$cohort->id, 'enrol'=>'cohort'), 'id ASC')) { + return true; + } + + $plugin = enrol_get_plugin('cohort'); + foreach ($enrols as $enrol) { + $plugin->delete_instance($enrol); + } + + return true; + } +} + +/** + * Sync all cohort course links. + * @param int $courseid one course, empty mean all + * @return void + */ +function enrol_cohort_sync($courseid = NULL) { + global $CFG, $DB; + + // unfortunately this may take a long time + @set_time_limit(0); //if this fails during upgrade we can continue from cron, no big deal + + $cohort = enrol_get_plugin('cohort'); + + $onecourse = $courseid ? "AND e.courseid = :courseid" : ""; + + // iterate through all not enrolled yet users + if (enrol_is_enabled('cohort')) { + $params = array(); + $onecourse = ""; + if ($courseid) { + $params['courseid'] = $courseid; + $onecourse = "AND e.courseid = :courseid"; + } + $sql = "SELECT cm.userid, e.id AS enrolid + FROM {cohort_members} cm + JOIN {enrol} e ON (e.customint1 = cm.cohortid AND e.status = :statusenabled AND e.enrol = 'cohort' $onecourse) + LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = cm.userid) + WHERE ue.id IS NULL"; + $params['statusenabled'] = ENROL_INSTANCE_ENABLED; + $params['courseid'] = $courseid; + $rs = $DB->get_recordset_sql($sql, $params); + $instances = array(); //cache + foreach($rs as $ue) { + if (!isset($instances[$ue->enrolid])) { + $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid)); + } + $cohort->enrol_user($instances[$ue->enrolid], $ue->userid); + } + $rs->close(); + unset($instances); + } + + // unenrol as necessary - ignore enabled flag, we want to get rid of all + $sql = "SELECT ue.userid, e.id AS enrolid + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'cohort' $onecourse) + LEFT JOIN {cohort_members} cm ON (cm.cohortid = e.customint1 AND cm.userid = ue.userid) + WHERE cm.id IS NULL"; + //TODO: this may use a bit of SQL optimisation + $rs = $DB->get_recordset_sql($sql, array('courseid'=>$courseid)); + $instances = array(); //cache + foreach($rs as $ue) { + if (!isset($instances[$ue->enrolid])) { + $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid)); + } + $cohort->unenrol_user($instances[$ue->enrolid], $ue->userid); + } + $rs->close(); + unset($instances); + + // now assign all necessary roles + if (enrol_is_enabled('cohort')) { + $sql = "SELECT e.roleid, ue.userid, c.id AS contextid, e.id AS itemid + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'cohort' AND e.status = :statusenabled $onecourse) + JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :coursecontext) + LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.userid = ue.userid AND ra.itemid = e.id AND ra.component = 'enrol_cohort' AND e.roleid = ra.roleid) + WHERE ra.id IS NULL"; + $params = array(); + $params['statusenabled'] = ENROL_INSTANCE_ENABLED; + $params['coursecontext'] = CONTEXT_COURSE; + $params['courseid'] = $courseid; + + $rs = $DB->get_recordset_sql($sql, $params); + foreach($rs as $ra) { + role_assign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_cohort', $ra->itemid); + } + $rs->close(); + } + + // remove unwanted roles - include ignored roles and disabled plugins too + $onecourse = $courseid ? "AND c.instanceid = :courseid" : ""; + $sql = "SELECT ra.roleid, ra.userid, ra.contextid, ra.itemid + FROM {role_assignments} ra + JOIN {context} c ON (c.id = ra.contextid AND c.contextlevel = :coursecontext $onecourse) + LEFT JOIN (SELECT e.id AS enrolid, e.roleid, ue.userid + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'cohort') + ) x ON (x.enrolid = ra.itemid AND ra.component = 'enrol_cohort' AND x.roleid = ra.roleid AND x.userid = ra.userid) + WHERE x.userid IS NULL AND ra.component = 'enrol_cohort'"; + $params = array('coursecontext' => CONTEXT_COURSE, 'courseid' => $courseid); + + $rs = $DB->get_recordset_sql($sql, $params); + foreach($rs as $ra) { + role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_cohort', $ra->itemid); + } + $rs->close(); + +} diff --git a/enrol/cohort/settings.php b/enrol/cohort/settings.php new file mode 100644 index 00000000000..07b1c97f631 --- /dev/null +++ b/enrol/cohort/settings.php @@ -0,0 +1,44 @@ +. + +/** + * Cohort enrolment plugin settings and presets. + * + * @package enrol_cohort + * @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_cohort_settings', '', get_string('pluginname_desc', 'enrol_cohort'))); + + + //--- enrol instance defaults ---------------------------------------------------------------------------- + if (!during_initial_install()) { + $options = get_default_enrol_roles(get_context_instance(CONTEXT_SYSTEM)); + $student = get_archetype_roles('student'); + $student = reset($student); + $settings->add(new admin_setting_configselect_with_advanced('enrol_cohort/roleid', + get_string('defaultrole', 'role'), '', + array('value'=>$student->id, 'adv'=>true), $options)); + } +} + diff --git a/enrol/cohort/version.php b/enrol/cohort/version.php new file mode 100644 index 00000000000..f992e51c2e0 --- /dev/null +++ b/enrol/cohort/version.php @@ -0,0 +1,27 @@ +. + +/** + * Cohort enrolment plugin version specification. + * + * @package enrol_cohort + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$plugin->version = 2010061500; +$plugin->cron = 60; \ No newline at end of file diff --git a/enrol/database/cli/sync.php b/enrol/database/cli/sync.php new file mode 100644 index 00000000000..e6daa145e87 --- /dev/null +++ b/enrol/database/cli/sync.php @@ -0,0 +1,40 @@ +. + +/** + * CLI sync for full external database synchronisation. + * + * @package enrol_database + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +if (isset($_SERVER['REMOTE_ADDR'])) { + error_log("enrol/database/cli/sync.php can not be called from web server!"); + exit; +} + +require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php'); + +if (!enrol_is_enabled('database')) { + die('enrol_database plugin is disabled, sync is disabled'); +} + + +$enrol = enrol_get_plugin('database'); +$enrol->sync_courses(); +$enrol->sync_enrolments(); diff --git a/enrol/database/config.html b/enrol/database/config.html deleted file mode 100644 index e7b28e7b483..00000000000 --- a/enrol/database/config.html +++ /dev/null @@ -1,251 +0,0 @@ -get_string('no'), '1'=>get_string('yes')); -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
enrol_dbtype: - enrol_dbtype)) { - $frm->enrol_dbtype = 'mysql'; - } - echo html_writer::select($dboptions, "enrol_dbtype", $frm->enrol_dbtype, false); - ?> - - - -
enrol_dbhost: - enrol_dbhost)) { - $frm->enrol_dbhost = ''; - } - ?> - - - -
enrol_dbuser: - - - -
enrol_dbpass: - - - -
enrol_dbname: - - - -
enrol_dbtable: - - - -
- -
enrol_localcoursefield: - - - -
enrol_localuserfield: - - - -
enrol_db_localrolefield: - - - -
enrol_remotecoursefield: - - - -
enrol_remoteuserfield: - - - -
enrol_db_remoterolefield: - - - -
- -
enrol_db_defaultcourseroleid: - get_string('default')) + $assignableroles; - - echo html_writer::select($assignableroles, 'enrol_db_defaultcourseroleid', $frm->enrol_db_defaultcourseroleid, false); - if (isset($err['enrol_db_defaultcourseroleid'])) echo $OUTPUT->error_text($err['enrol_db_defaultcourseroleid']); - ?> - - -
- -
enrol_db_autocreate: - enrol_db_autocreate, false); - if (isset($err["enrol_db_autocreate"])) echo $OUTPUT->error_text($err["enrol_db_autocreate"]); - ?> - - -
enrol_db_category: - enrol_db_category, false); - - ?> - error_text($err["enrol_db_category"]); ?> - - -
enrol_db_template: - - error_text($err["enrol_db_template"]); ?> - - -
- -
enrol_db_ignorehiddencourse: - enrol_db_ignorehiddencourse, false); - if (isset($err['enrol_db_ignorehiddencourse'])) { - echo $OUTPUT->error_text($err['enrol_db_ignorehiddencourse']); - } - ?> - - -
enrol_db_disableunenrol: - enrol_db_disableunenrol, false); - if (isset($err['enrol_db_disableunenrol'])) { - echo $OUTPUT->error_text($err['enrol_db_disableunenrol']); - } - ?> - - -
diff --git a/enrol/database/db/access.php b/enrol/database/db/access.php new file mode 100644 index 00000000000..4ccb27b2d91 --- /dev/null +++ b/enrol/database/db/access.php @@ -0,0 +1,45 @@ +. + +/** + * Capabilities for database enrolment plugin. + * + * @package enrol_database + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$capabilities = array( + 'enrol/database:config' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'manager' => CAP_ALLOW, + ) + ), + + 'enrol/database:manage' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'manager' => CAP_ALLOW, + ) + ), + +); + + diff --git a/enrol/database/db/install.php b/enrol/database/db/install.php new file mode 100644 index 00000000000..5d974ede90c --- /dev/null +++ b/enrol/database/db/install.php @@ -0,0 +1,107 @@ +. + +/** + * Database enrolment plugin installation. + * + * @package enrol_database + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +function xmldb_enrol_database_install() { + global $CFG, $DB; + + // migrate old config settings first + if (isset($CFG->enrol_dbtype)) { + set_config('dbtype', $CFG->enrol_dbtype, 'enrol_database'); + unset_config('enrol_dbtype'); + } + if (isset($CFG->enrol_dbhost)) { + set_config('dbhost', $CFG->enrol_dbhost, 'enrol_database'); + unset_config('enrol_dbhost'); + } + if (isset($CFG->enrol_dbuser)) { + set_config('dbuser', $CFG->enrol_dbuser, 'enrol_database'); + unset_config('enrol_dbuser'); + } + if (isset($CFG->enrol_dbpass)) { + set_config('dbpass', $CFG->enrol_dbpass, 'enrol_database'); + unset_config('enrol_dbpass'); + } + if (isset($CFG->enrol_dbname)) { + set_config('dbname', $CFG->enrol_dbname, 'enrol_database'); + unset_config('enrol_dbname'); + } + if (isset($CFG->enrol_dbtable)) { + set_config('remoteenroltable', $CFG->enrol_dbtable, 'enrol_database'); + unset_config('enrol_dbtable'); + } + if (isset($CFG->enrol_localcoursefield)) { + set_config('localcoursefield', $CFG->enrol_localcoursefield, 'enrol_database'); + unset_config('enrol_localcoursefield'); + } + if (isset($CFG->enrol_localuserfield)) { + set_config('localuserfield', $CFG->enrol_localuserfield, 'enrol_database'); + unset_config('enrol_localuserfield'); + } + if (isset($CFG->enrol_localrolefield)) { + set_config('localrolefield', $CFG->enrol_localrolefield, 'enrol_database'); + unset_config('enrol_localrolefield'); + } + if (isset($CFG->enrol_remotecoursefield)) { + set_config('remotecoursefield', $CFG->enrol_remotecoursefield, 'enrol_database'); + unset_config('enrol_remotecoursefield'); + } + if (isset($CFG->enrol_remoteuserfield)) { + set_config('remoteuserfield', $CFG->enrol_remoteuserfield, 'enrol_database'); + unset_config('enrol_remoteuserfield'); + } + if (isset($CFG->enrol_remoterolefield)) { + set_config('remoterolefield', $CFG->enrol_remoterolefield, 'enrol_database'); + unset_config('enrol_remoterolefield'); + } + if (isset($CFG->enrol_db_defaultcourseroleid)) { + set_config('defaultrole', $CFG->enrol_db_defaultcourseroleid, 'enrol_database'); + unset_config('enrol_db_defaultcourseroleid'); + } + unset_config('enrol_db_autocreate'); // replaced by new coruse temple sync + if (isset($CFG->enrol_db_category)) { + set_config('defaultcategory', $CFG->enrol_db_category, 'enrol_database'); + unset_config('enrol_db_category'); + } + if (isset($CFG->enrol_db_template)) { + set_config('templatecourse', $CFG->enrol_db_template, 'enrol_database'); + unset_config('enrol_db_template'); + } + if (isset($CFG->enrol_db_ignorehiddencourse)) { + set_config('ignorehiddencourses', $CFG->enrol_db_ignorehiddencourse, 'enrol_database'); + unset_config('enrol_db_ignorehiddencourse'); + } + + + + + + + + // just make sure there are no leftovers after disabled plugin + if (!$DB->record_exists('enrol', array('enrol'=>'database'))) { + role_unassign_all(array('component'=>'enrol_database')); + return; + } +} diff --git a/enrol/database/enrol.php b/enrol/database/enrol.php deleted file mode 100644 index 594f82d44cc..00000000000 --- a/enrol/database/enrol.php +++ /dev/null @@ -1,681 +0,0 @@ -libdir.'/adodb/adodb.inc.php'); -require_once($CFG->dirroot.'/enrol/enrol.class.php'); - -class enrolment_plugin_database { - - var $log; - -/** - * For the given user, let's go out and look in an external database - * for an authoritative list of enrolments, and then adjust the - * local Moodle assignments to match. - */ -function setup_enrolments(&$user) { - global $CFG, $DB; - - // NOTE: if $this->enrol_connect() succeeds you MUST remember to call - // $this->enrol_disconnect() as it is doing some nasty vodoo with table prefix - $enroldb = $this->enrol_connect(); - if (!$enroldb) { - error_log('[ENROL_DB] Could not make a connection'); - return; - } - - // If we are expecting to get role information from our remote db, then - // we execute the below code for every role type. Otherwise we just - // execute it once with null (hence the dummy array). - $roles = !empty($CFG->enrol_db_remoterolefield) && !empty($CFG->enrol_db_localrolefield) - ? get_all_roles() - : array(null); - - //error_log('[ENROL_DB] found ' . count($roles) . ' roles:'); - - foreach($roles as $role) { - - //error_log('[ENROL_DB] setting up enrolments for '.$role->shortname); - - /// Get the authoritative list of enrolments from the external database table - /// We're using the ADOdb functions natively here and not our datalib functions - /// because we didn't want to mess with the $ db global - - $useridfield = $enroldb->quote($user->{$CFG->enrol_localuserfield}); - - list($have_role, $remote_role_name, $remote_role_value) = $this->role_fields($enroldb, $role); - - /// Check if a particular role has been forced by the plugin site-wide - /// (if we aren't doing a role-based select) - if (!$have_role && $CFG->enrol_db_defaultcourseroleid) { - $role = $DB->get_record('role', array('id'=>$CFG->enrol_db_defaultcourseroleid)); - } - - /// Whether to fetch the default role on a per-course basis (below) or not. - $use_default_role = !$role; - - /* - if ($have_role) { - error_log('[ENROL_DB] Doing role-specific select from db for role: '.$role->shortname); - } elseif ($use_default_role) { - error_log('[ENROL_DB] Using course default for roles - assuming that database lists defaults'); - } else { - error_log('[ENROL_DB] Using config default for roles: '.$role->shortname); - }*/ - - if ($rs = $enroldb->Execute("SELECT {$CFG->enrol_remotecoursefield} as enrolremotecoursefield - FROM {$CFG->enrol_dbtable} - WHERE {$CFG->enrol_remoteuserfield} = " . $useridfield . - (isset($remote_role_name, $remote_role_value) ? ' AND '.$remote_role_name.' = '.$remote_role_value : ''))) { - - // We'll use this to see what to add and remove - $existing = $role - ? $DB->get_records_sql("SELECT * - FROM {role_assignments} - WHERE userid = ? AND roleid = ?", - array($user->id, $role->id)) - : $DB->get_records('role_assignments', array('userid'=>$user->id)); - - if (!$existing) { - $existing = array(); - } - - - if (!$rs->EOF) { // We found some courses - - //$count = 0; - $courselist = array(); - while ($fields = $rs->FetchRow()) { // Make a nice little array of courses to process - $fields = array_change_key_case($fields, CASE_LOWER); - $courselist[] = $fields['enrolremotecoursefield']; - //$count++; - } - $rs->close(); - - //error_log('[ENROL_DB] Found '.count($existing).' existing roles and '.$count.' in external database'); - - foreach ($courselist as $coursefield) { /// Check the list of courses against existing - $course = $DB->get_record('course', array($CFG->enrol_localcoursefield=>$coursefield)); - if (!is_object($course)) { - if (empty($CFG->enrol_db_autocreate)) { // autocreation not allowed - if (debugging('',DEBUG_ALL)) { - error_log( "Course $coursefield does not exist, skipping") ; - } - continue; // next foreach course - } - // ok, now then let's create it! - // prepare any course properties we actually have - $course = new StdClass; - $course->{$CFG->enrol_localcoursefield} = $coursefield; - $course->fullname = $coursefield; - $course->shortname = $coursefield; - if (!($newcourseid = $this->create_course($course, true) - and $course = $DB->get_record( 'course', array('id'=>$newcourseid)))) { - error_log( "Creating course $coursefield failed"); - continue; // nothing left to do... - } - } - - // if the course is hidden and we don't want to enrol in hidden courses - // then just skip it - if (!$course->visible and $CFG->enrol_db_ignorehiddencourse) { - continue; - } - - /// If there's no role specified, we get the default course role (usually student) - if ($use_default_role) { - $role = get_default_course_role($course); - } - - $context = get_context_instance(CONTEXT_COURSE, $course->id); - - // Couldn't get a role or context, skip. - if (!$role || !$context) { - continue; - } - - // Search the role assignments to see if this user - // already has this role in this context. If it is, we - // skip to the next course. - foreach($existing as $key => $role_assignment) { - if ($role_assignment->roleid == $role->id - && $role_assignment->contextid == $context->id) { - unset($existing[$key]); - //error_log('[ENROL_DB] User is already enroled in course '.$course->idnumber); - continue 2; - } - } - - //error_log('[ENROL_DB] Enrolling user in course '.$course->idnumber); - role_assign($role->id, $user->id, 0, $context->id, 0, 0, 0, 'database'); - } - } // We've processed all external courses found - - /// We have some courses left that we might need to unenrol from - /// Note: we only process enrolments that we (ie 'database' plugin) made - /// Do not unenrol anybody if the disableunenrol option is 'yes' - if (!$CFG->enrol_db_disableunenrol) { - foreach ($existing as $role_assignment) { - if ($role_assignment->enrol == 'database') { - //error_log('[ENROL_DB] Removing user from context '.$role_assignment->contextid); - role_unassign($role_assignment->roleid, $user->id, '', $role_assignment->contextid); - } - } - } - } else { - error_log('[ENROL_DB] Couldn\'t get rows from external db: '.$enroldb->ErrorMsg()); - } - } - $this->enrol_disconnect($enroldb); -} - -/** - * sync enrolments with database, create courses if required. - * - * @param object The role to sync for. If no role is specified, defaults are - * used. - */ -function sync_enrolments($role = null) { - global $CFG, $DB, $OUTPUT; - error_reporting(E_ALL); - - // Connect to the external database - $enroldb = $this->enrol_connect(); - if (!$enroldb) { - echo $OUTPUT->notification("enrol/database cannot connect to server"); - return false; - } - - if (isset($role)) { - echo '=== Syncing enrolments for role: '.$role->shortname." ===\n"; - } else { - echo "=== Syncing enrolments for default role ===\n"; - } - - // first, pack the sortorder... - fix_course_sortorder(); - - list($have_role, $remote_role_name, $remote_role_value) = $this->role_fields($enroldb, $role); - - if (!$have_role) { - if (!empty($CFG->enrol_db_defaultcourseroleid) - and $role = $DB->get_record('role', array('id'=>$CFG->enrol_db_defaultcourseroleid))) { - echo "=== Using enrol_db_defaultcourseroleid: {$role->id} ({$role->shortname}) ===\n"; - } elseif (isset($role)) { - echo "!!! WARNING: Role specified by caller, but no (or invalid) role configuration !!!\n"; - } - } - - // get enrolments per-course - $sql = "SELECT DISTINCT {$CFG->enrol_remotecoursefield} " . - " FROM {$CFG->enrol_dbtable} " . - " WHERE {$CFG->enrol_remoteuserfield} IS NOT NULL" . - (isset($remote_role_name, $remote_role_value) ? ' AND '.$remote_role_name.' = '.$remote_role_value : ''); - - $rs = $enroldb->Execute($sql); - if (!$rs) { - trigger_error($enroldb->ErrorMsg() .' STATEMENT: '. $sql); - return false; - } - if ( $rs->EOF ) { // no courses! outta here... - return true; - } - - $transaction = $DB->start_delegated_transaction(); - - $extcourses = array(); - while ($rsextcourse = $rs->FetchRow()) { // there are more course records - $rsextcourse = array_change_key_case($rsextcourse, CASE_LOWER); - $extcourse = $rsextcourse[strtolower($CFG->enrol_remotecoursefield)]; - array_push($extcourses, $extcourse); - - // does the course exist in moodle already? - $course = false; - $course = $DB->get_record('course', array($CFG->enrol_localcoursefield=>$extcourse)); - - if (!is_object($course)) { - if (empty($CFG->enrol_db_autocreate)) { // autocreation not allowed - if (debugging('', DEBUG_ALL)) { - error_log( "Course $extcourse does not exist, skipping"); - } - continue; // next foreach course - } - // ok, now then let's create it! - // prepare any course properties we actually have - $course = new StdClass; - $course->{$CFG->enrol_localcoursefield} = $extcourse; - $course->fullname = $extcourse; - $course->shortname = $extcourse; - if (!($newcourseid = $this->create_course($course, true) - and $course = $DB->get_record('course', array('id'=>$newcourseid)))) { - error_log( "Creating course $extcourse failed"); - continue; // nothing left to do... - } - - } - - $context = get_context_instance(CONTEXT_COURSE, $course->id); - - // If we don't have a proper role setup, then we default to the default - // role for the current course. - if (!$have_role) { - $role = get_default_course_role($course); - } - - // get a list of the student ids the are enrolled - // in the external db -- hopefully it'll fit in memory... - $extenrolments = array(); - $sql = "SELECT {$CFG->enrol_remoteuserfield} " . - " FROM {$CFG->enrol_dbtable} " . - " WHERE {$CFG->enrol_remotecoursefield} = " . $enroldb->quote($extcourse) . - ($have_role ? ' AND '.$remote_role_name.' = '.$remote_role_value : ''); - - $crs = $enroldb->Execute($sql); - if (!$crs) { - trigger_error($enroldb->ErrorMsg() .' STATEMENT: '. $sql); - return false; - } - if ( $crs->EOF ) { // shouldn't happen, but cover all bases - continue; - } - - // slurp results into an array - while ($rscrs = $crs->FetchRow()) { - $rscrs = array_change_key_case($rscrs, CASE_LOWER); - array_push($extenrolments, $rscrs[strtolower($CFG->enrol_remoteuserfield)]); - } - $crs->close(); // release the handle - - // - // prune enrolments to users that are no longer in ext auth - // hopefully they'll fit in the max buffer size for the RDBMS - // - // TODO: This doesn't work perfectly. If we are operating without - // roles in the external DB, then this doesn't handle changes of role - // within a course (because the user is still enrolled in the course, - // so NOT IN misses the course). - // - // When the user logs in though, their role list will be updated - // correctly. - // - if (!$CFG->enrol_db_disableunenrol) { - if ($extenrolments) { - list($extlist, $params) = $DB->get_in_or_equal($extenrolments, SQL_PARAMS_NAMED, 'e0', false); - $extsql = "AND u.{$CFG->enrol_localuserfield} $extlist"; - } else { - $extsql = ""; - $params = array(); - } - $params['roleid'] = $role->id; - $params['contextid'] = $context->id; - - $to_prune = $DB->get_records_sql(" - SELECT ra.* - FROM {role_assignments} ra - JOIN {user} u ON ra.userid = u.id - WHERE ra.enrol = 'database' - AND ra.contextid = :contextid - AND ra.roleid = :roleid", $params); - - if ($to_prune) { - foreach ($to_prune as $role_assignment) { - if (role_unassign($role->id, $role_assignment->userid, 0, $role_assignment->contextid)){ - error_log( "Unassigned {$role->shortname} assignment #{$role_assignment->id} for course {$course->id} (" . format_string($course->shortname) . "); user {$role_assignment->userid}"); - } else { - error_log( "Failed to unassign {$role->shortname} assignment #{$role_assignment->id} for course {$course->id} (" . format_string($course->shortname) . "); user {$role_assignment->userid}"); - } - } - } - } - - // - // insert current enrolments - // bad we can't do INSERT IGNORE with postgres... - // - foreach ($extenrolments as $member) { - // Get the user id and whether is enrolled in one fell swoop - $sql = " - SELECT u.id, ra.id AS enrolmentid - FROM {user} u - LEFT JOIN {role_assignments} ra ON u.id = ra.userid - AND ra.roleid = ? - AND ra.contextid = ? - WHERE u.{$CFG->enrol_localuserfield} = ? - AND (u.deleted IS NULL OR u.deleted=0)"; - - $eusers = $DB->get_records($sql, array($role->id, $context->id, $member)); - if ($eusers === false) { - trigger_error('error STATEMENT: '. $sql); - return false; - } - if (!$eusers) { // if this returns empty, it means we don't have the student record. - // should not happen -- but skip it anyway - trigger_error('weird! no user record entry?'); - continue; - } - $userid = $user_obj->id; - $enrolmentid = $user_obj->enrolmentid; - - if ($enrolmentid) { // already enrolled - skip - continue; - } - - if (role_assign($role->id, $userid, 0, $context->id, 0, 0, 0, 'database')){ - error_log( "Assigned role {$role->shortname} to user {$userid} in course {$course->id} (" . format_string($course->shortname) . ")"); - } else { - error_log( "Failed to assign role {$role->shortname} to user {$userid} in course {$course->id} (" . format_string($course->shortname) . ")"); - } - - } // end foreach member - } // end while course records - $rs->close(); //Close the main course recordset - - // - // prune enrolments to courses that are no longer in ext auth - // - // TODO: This doesn't work perfectly. If we are operating without - // roles in the external DB, then this doesn't handle changes of role - // within a course (because the user is still enrolled in the course, - // so NOT IN misses the course). - // - // When the user logs in though, their role list will be updated - // correctly. - // - if (!$CFG->enrol_db_disableunenrol) { - if ($extcourses) { - list($extlist, $params) = $DB->get_in_or_equal($extcourses, SQL_PARAMS_QM, 'e0', false); - $extsql = "AND u.{$CFG->enrol_localcoursefield} $extlist"; - } else { - $extsql = ""; - $params = array(); - } - $params['roleid'] = $role->id; - $params['contextid'] = $context->id; - - $sql = " - SELECT ra.roleid, ra.userid, ra.contextid - FROM {role_assignments} ra - JOIN {context} cn ON cn.id = ra.contextid - JOIN {course} c ON c.id = cn.instanceid - WHERE ra.enrol = 'database' - AND cn.contextlevel = ".CONTEXT_COURSE." " . - ($have_role ? " AND ra.roleid = :roleid " : '') ." - $extsql"; - - if (!$ers = $DB->get_recordset_sql($sql, $params)) { - trigger_error('error STATEMENT: '. $sql); - return false; - } - foreach ($ers as $user_obj) { - $roleid = $user_obj->roleid; - $user = $user_obj->userid; - $contextid = $user_obj->contextid; - if (role_unassign($roleid, $user, 0, $contextid)){ - error_log( "Unassigned role {$roleid} from user $user in context $contextid"); - } else { - error_log( "Failed unassign role {$roleid} from user $user in context $contextid"); - } - } - $ers->close(); // release the handle - } - - $transaction->allow_commit(); - - // we are done now, a bit of housekeeping - fix_course_sortorder(); - - $this->enrol_disconnect($enroldb); - return true; -} - -/// Overide the get_access_icons() function -function get_access_icons($course) { -} - - -/// Overide the base config_form() function -function config_form($frm) { - global $CFG, $OUTPUT; - - $vars = array('enrol_dbhost', 'enrol_dbuser', 'enrol_dbpass', - 'enrol_dbname', 'enrol_dbtable', - 'enrol_localcoursefield', 'enrol_localuserfield', - 'enrol_remotecoursefield', 'enrol_remoteuserfield', - 'enrol_db_autocreate', 'enrol_db_category', 'enrol_db_template', - 'enrol_db_localrolefield', 'enrol_db_remoterolefield', - 'enrol_remotecoursefield', 'enrol_remoteuserfield', - 'enrol_db_ignorehiddencourse', 'enrol_db_defaultcourseroleid', - 'enrol_db_disableunenrol'); - - foreach ($vars as $var) { - if (!isset($frm->$var)) { - $frm->$var = ''; - } - } - include("$CFG->dirroot/enrol/database/config.html"); -} - -/// Override the base process_config() function -function process_config($config) { - - if (!isset($config->enrol_dbtype)) { - $config->enrol_dbtype = 'mysql'; - } - set_config('enrol_dbtype', $config->enrol_dbtype); - - if (!isset($config->enrol_dbhost)) { - $config->enrol_dbhost = ''; - } - set_config('enrol_dbhost', $config->enrol_dbhost); - - if (!isset($config->enrol_dbuser)) { - $config->enrol_dbuser = ''; - } - set_config('enrol_dbuser', $config->enrol_dbuser); - - if (!isset($config->enrol_dbpass)) { - $config->enrol_dbpass = ''; - } - set_config('enrol_dbpass', $config->enrol_dbpass); - - if (!isset($config->enrol_dbname)) { - $config->enrol_dbname = ''; - } - set_config('enrol_dbname', $config->enrol_dbname); - - if (!isset($config->enrol_dbtable)) { - $config->enrol_dbtable = ''; - } - set_config('enrol_dbtable', $config->enrol_dbtable); - - if (!isset($config->enrol_localcoursefield)) { - $config->enrol_localcoursefield = ''; - } - set_config('enrol_localcoursefield', $config->enrol_localcoursefield); - - if (!isset($config->enrol_localuserfield)) { - $config->enrol_localuserfield = ''; - } - set_config('enrol_localuserfield', $config->enrol_localuserfield); - - if (!isset($config->enrol_remotecoursefield)) { - $config->enrol_remotecoursefield = ''; - } - set_config('enrol_remotecoursefield', $config->enrol_remotecoursefield); - - if (!isset($config->enrol_remoteuserfield)) { - $config->enrol_remoteuserfield = ''; - } - set_config('enrol_remoteuserfield', $config->enrol_remoteuserfield); - - if (!isset($config->enrol_db_autocreate)) { - $config->enrol_db_autocreate = ''; - } - set_config('enrol_db_autocreate', $config->enrol_db_autocreate); - - if (!isset($config->enrol_db_category)) { - $config->enrol_db_category = ''; - } - set_config('enrol_db_category', $config->enrol_db_category); - - if (!isset($config->enrol_db_template)) { - $config->enrol_db_template = ''; - } - set_config('enrol_db_template', $config->enrol_db_template); - - if (!isset($config->enrol_db_defaultcourseroleid)) { - $config->enrol_db_defaultcourseroleid = ''; - } - set_config('enrol_db_defaultcourseroleid', $config->enrol_db_defaultcourseroleid); - - if (!isset($config->enrol_db_localrolefield)) { - $config->enrol_db_localrolefield = ''; - } - set_config('enrol_db_localrolefield', $config->enrol_db_localrolefield); - - if (!isset($config->enrol_db_remoterolefield)) { - $config->enrol_db_remoterolefield = ''; - } - set_config('enrol_db_remoterolefield', $config->enrol_db_remoterolefield); - - if (!isset($config->enrol_db_ignorehiddencourse)) { - $config->enrol_db_ignorehiddencourse = ''; - } - set_config('enrol_db_ignorehiddencourse', $config->enrol_db_ignorehiddencourse ); - - if (!isset($config->enrol_db_disableunenrol)) { - $config->enrol_db_disableunenrol = ''; - } - set_config('enrol_db_disableunenrol', $config->enrol_db_disableunenrol ); - - return true; -} - -// will create the moodle course from the template -// course_ext is an array as obtained from ldap -- flattened somewhat -// NOTE: if you pass true for $skip_fix_course_sortorder -// you will want to call fix_course_sortorder() after your are done -// with course creation -function create_course ($course,$skip_fix_course_sortorder=0){ - global $CFG, $DB, $OUTPUT; - - // define a template - if (!empty($CFG->enrol_db_template)){ - $template = $DB->get_record("course", array('shortname'=>$CFG->enrol_db_template)); - $template = (array)$template; - } else { - $site = get_site(); - $template = array( - 'startdate' => time() + 3600 * 24, - 'summary' => get_string("defaultcoursesummary"), - 'format' => "weeks", - 'password' => "", - 'guest' => 0, - 'numsections' => 10, - 'idnumber' => '', - 'cost' => '', - 'newsitems' => 5, - 'showgrades' => 1, - 'groupmode' => 0, - 'groupmodeforce' => 0, - ); - } - // overlay template - foreach (array_keys($template) AS $key) { - if (empty($course->$key)) { - $course->$key = $template[$key]; - } - } - - $category = get_course_category($CFG->enrol_db_category); - - // put at the end of category - $course->sortorder = $category->sortorder + MAX_COURSES_IN_CATEGORY - 1; - - // override with local data - $course->startdate = time() + 3600 * 24; - $course->timecreated = time(); - $course->visible = 1; - - // clear out id just in case - unset($course->id); - - // truncate a few key fields - $course->idnumber = substr($course->idnumber, 0, 100); - $course->shortname = substr($course->shortname, 0, 100); - - // store it and log - if ($newcourseid = $DB->insert_record("course", $course)) { // Set up new course - $section = new object(); - $section->course = $newcourseid; // Create a default section. - $section->section = 0; - $section->summaryformat = FORMAT_HTML; - $section->id = $DB->insert_record("course_sections", $section); - $course = $DB->get_record('course', array('id' => $newcourseid)); - blocks_add_default_course_blocks($course); - - if (!$skip_fix_course_sortorder){ - fix_course_sortorder(); - } - add_to_log($newcourseid, "course", "new", "view.php?id=$newcourseid", "enrol/database auto-creation"); - } else { - trigger_error("Could not create new course $extcourse from from database"); - echo $OUTPUT->notification("Serious Error! Could not create the new course!"); - return false; - } - - return $newcourseid; -} - -/// DB Connect -/// NOTE: You MUST remember to disconnect -/// when you stop using it -- as this call will -/// sometimes modify table prefix for the whole of Moodle! -function enrol_connect() { - global $CFG; - - // Try to connect to the external database (forcing new connection) - $enroldb = &ADONewConnection($CFG->enrol_dbtype); - if ($enroldb->Connect($CFG->enrol_dbhost, $CFG->enrol_dbuser, $CFG->enrol_dbpass, $CFG->enrol_dbname, true)) { - $enroldb->SetFetchMode(ADODB_FETCH_ASSOC); ///Set Assoc mode always after DB connection - return $enroldb; - } else { - trigger_error("Error connecting to enrolment DB backend with: " - . "$CFG->enrol_dbhost,$CFG->enrol_dbuser,$CFG->enrol_dbpass,$CFG->enrol_dbname"); - return false; - } -} - -/// DB Disconnect -function enrol_disconnect($enroldb) { - global $CFG; - - $enroldb->Close(); -} - -/** - * This function returns the name and value of the role field to query the db - * for, or null if there isn't one. - * - * @param object The ADOdb connection - * @param object The role - * @return array (boolean, string, db quoted string) - */ -function role_fields($enroldb, $role) { - global $CFG; - - if ($have_role = !empty($role) - && !empty($CFG->enrol_db_remoterolefield) - && !empty($CFG->enrol_db_localrolefield) - && !empty($role->{$CFG->enrol_db_localrolefield})) { - $remote_role_name = $CFG->enrol_db_remoterolefield; - $remote_role_value = $enroldb->quote($role->{$CFG->enrol_db_localrolefield}); - } else { - $remote_role_name = $remote_role_value = null; - } - - return array($have_role, $remote_role_name, $remote_role_value); -} - -} // end of class - - diff --git a/enrol/database/enrol_database_sync.php b/enrol/database/enrol_database_sync.php deleted file mode 100644 index 8e2fa82ac9f..00000000000 --- a/enrol/database/enrol_database_sync.php +++ /dev/null @@ -1,41 +0,0 @@ -dirroot . '/course/lib.php'); - require_once($CFG->dirroot . '/enrol/database/enrol.php'); - - // ensure errors are well explained - $CFG->debug=E_ALL; - - if (!is_enabled_enrol('database')) { - error_log("Database enrol plugin not enabled!"); - die; - } - - // update enrolments -- these handlers should autocreate courses if required - $enrol = new enrolment_plugin_database(); - - // If we have settings to handle roles individually, through each type of - // role and update it. Otherwise, just got through once (with no role - // specified). - $roles = !empty($CFG->enrol_db_remoterolefield) && !empty($CFG->enrol_db_localrolefield) - ? get_all_roles() - : array(null); - - foreach ($roles as $role) { - $enrol->sync_enrolments($role); - } - - // sync metacourses - if (function_exists('sync_metacourses')) { - sync_metacourses(); - } - - diff --git a/enrol/database/lang/en/enrol_database.php b/enrol/database/lang/en/enrol_database.php index e42fbe3d9bc..2f65c805874 100644 --- a/enrol/database/lang/en/enrol_database.php +++ b/enrol/database/lang/en/enrol_database.php @@ -23,46 +23,55 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -$string['autocreate'] = 'Courses can be created automatically if there are enrolments to a course that doesn\'t yet exist in Moodle.'; -$string['autocreation_settings'] = 'Autocreation Settings'; -$string['category'] = 'The category for auto-created courses.'; -$string['course_fullname'] = 'The name of the field where the course fullname is stored.'; -$string['course_id'] = 'The name of the field where the course ID is stored. The values of this field are used to match those in the "enrol_db_l_coursefield" field in Moodle\'s course table.'; -$string['course_shortname'] = 'The name of the field where the course shortname is stored.'; -$string['course_table'] = 'Then name of the table where we expect to find the course details in (short name, fullname, ID, etc.)'; -$string['dbhost'] = 'Server IP name or number'; +$string['database:config'] = 'Configure external database enrol instances'; +$string['database:manage'] = 'Manage external database enrol instances'; +$string['dbencoding'] = 'Database encoding'; +$string['dbhost'] = 'Database host'; +$string['dbhost_desc'] = 'Type database server IP address or host name'; $string['dbname'] = 'Database name'; -$string['dbpass'] = 'Server password'; -$string['dbtable'] = 'Database table'; -$string['dbtype'] = 'Database type'; -$string['dbuser'] = 'Server user'; -$string['defaultcourseroleid'] = 'The role that will be assigned by default if no other role is specified.'; -$string['description'] = 'You can use a external database (of nearly any kind) to control your enrolments. It is assumed your external database contains a field containing a course ID, and a field containing a user ID. These are compared against fields that you choose in the local course and user tables.'; -$string['disableunenrol'] = 'If set to yes users previously enrolled by the external database plugin will not be unenrolled by the same plugin regardless of the database contents.'; -$string['enrol_database_autocreation_settings'] = 'Auto-creation of new courses'; -$string['enrolname'] = 'External Database'; -$string['general_options'] = 'General Options'; -$string['host'] = 'Database server hostname.'; -$string['ignorehiddencourse'] = 'If set to yes users will not be enroled on courses that are set to be unavailable to students.'; -$string['localcoursefield'] = 'The name of the field in the course table that we are using to match entries in the remote database (eg idnumber).'; -$string['local_fields_mapping'] = 'Moodle (local) database fields'; -$string['localrolefield'] = 'The name of the field in the roles table that we are using to match entries in the remote database (eg shortname).'; -$string['localuserfield'] = 'The name of the field in the user table that we are using to match entries in the remote database (eg idnumber).'; -$string['name'] = 'The specific database to use.'; -$string['pass'] = 'Password to access the server.'; -$string['remotecoursefield'] = 'The name of the field in the remote table that we are using to match entries in the course table.'; -$string['remote_fields_mapping'] = 'Enrolment (remote) database fields.'; -$string['remoterolefield'] = 'The name of the field in the remote table that we are using to match entries in the roles table.'; -$string['remoteuserfield'] = 'The name of the field in the remote table that we are using to match entries in the user table.'; -$string['server_settings'] = 'External Database Server Settings'; -$string['student_coursefield'] = 'The name of the field in the student enrolment table that we expect to find the course ID in.'; -$string['student_l_userfield'] = 'The name of the field in the local user table that we use to match the user to a remote record for students (eg idnumber).'; -$string['student_r_userfield'] = 'The name of the field in the remote student enrolment table that we expect to find the user ID in.'; -$string['student_table'] = 'The name of the table where student enrolments are stored.'; -$string['teacher_coursefield'] = 'The name of the field in the teacher enrolment table that we expect to find the course ID in.'; -$string['teacher_l_userfield'] = 'The name of the field in the local user table that we use to match the user to a remote record for teachers (eg idnumber).'; -$string['teacher_r_userfield'] = 'The name of the field in the remote teacher enrolment table that we expect to find the user ID in.'; -$string['teacher_table'] = 'The name of the table where teacher enrolments are stored.'; -$string['template'] = 'Optional: auto-created courses can copy their settings from a template course. Type here the shortname of the template course.'; -$string['type'] = 'Database server type.'; -$string['user'] = 'Username to access the server.'; +$string['dbpass'] = 'Database password'; +$string['dbsetupsql'] = 'Database setup command'; +$string['dbsetupsql_desc'] = 'SQL command for special database setup, often used to setup communication encoding - example for MySQL and PostgreSQL: SET NAMES \'utf8\''; +$string['dbsybasequoting'] = 'Use sybase quotes'; +$string['dbsybasequoting_desc'] = 'Sybase style single quote escaping - needed for Oracle, MS SQL and some other databases. Do not use for MySQL!'; +$string['dbtype'] = 'Database driver'; +$string['dbtype_desc'] = 'ADOdb database driver name, type of the external database engine.'; +$string['dbuser'] = 'Database user'; +$string['debugdb'] = 'Debug ADOdb'; +$string['debugdb_desc'] = 'Debug ADOdb connection to external database - use when getting empty page during login. Not suitable for production sites!'; +$string['defaultcategory'] = 'Default new course category'; +$string['defaultcategory_desc'] = 'The default category for auto-created courses. Used when no new category id specified or not found.'; +$string['defaultrole'] = 'Default role'; +$string['defaultrole_desc'] = 'The role that will be assigned by default if no other role is specified in external table.'; +$string['ignorehiddencourses'] = 'Ignore hidden courses'; +$string['ignorehiddencourses_desc'] = 'If enabled users will not be enrolled on courses that are set to be unavailable to students.'; +$string['localcoursefield'] = 'Local course field'; +$string['localrolefield'] = 'Local role field'; +$string['localuserfield'] = 'Local user field'; +$string['newcoursetable'] = 'Remote new courses table'; +$string['newcoursetable_desc'] = 'Specify of the name of the table that contains list of courses that should be created automatically. Empty means no courses are created.'; +$string['newcoursecategory'] = 'New course category id field'; +$string['newcoursefullname'] = 'New course full name field'; +$string['newcourseidnumber'] = 'New course ID number field'; +$string['newcourseshortname'] = 'New course short name field'; +$string['pluginname'] = 'External database'; +$string['pluginname_desc'] = 'You can use an external database (of nearly any kind) to control your enrolments. It is assumed your external database contains at least a field containing a course ID, and a field containing a user ID. These are compared against fields that you choose in the local course and user tables.'; +$string['remotecoursefield'] = 'Remote course field'; +$string['remotecoursefield_desc'] = 'The name of the field in the remote table that we are using to match entries in the course table.'; +$string['remoteenroltable'] = 'Remote user enrolment table'; +$string['remoteenroltable_desc'] = 'Specify the name of the table that contains list of user enrolments. Empty means no user enrolment sync.'; +$string['remoterolefield'] = 'Remote role field'; +$string['remoterolefield_desc'] = 'The name of the field in the remote table that we are using to match entries in the roles table.'; +$string['remoteuserfield'] = 'Remote user field'; +$string['settingsheaderdb'] = 'External database connection'; +$string['settingsheaderlocal'] = 'Local field mapping'; +$string['settingsheaderremote'] = 'Remote enrolment sync'; +$string['settingsheadernewcourses'] = 'Creation of new courses'; +$string['remoteuserfield_desc'] = 'The name of the field in the remote table that we are using to match entries in the user table.'; +$string['templatecourse'] = 'New course template'; +$string['templatecourse_desc'] = 'Optional: auto-created courses can copy their settings from a template course. Type here the shortname of the template course.'; +$string['unenrolaction'] = 'External unenrol action'; +$string['unenrolaction_desc'] = 'Select action to carry our when user enrolment disappears from external enrolment table. Please note that some user data and settings are purged from course during course unenrolment.'; +$string['unenrolactiondisable'] = 'Disable course enrolment'; +$string['unenrolactionkeep'] = 'Keep user enrolled'; +$string['unenrolactionunenrol'] = 'Unenrol user from course'; diff --git a/enrol/database/lib.php b/enrol/database/lib.php new file mode 100644 index 00000000000..07b4fd49795 --- /dev/null +++ b/enrol/database/lib.php @@ -0,0 +1,487 @@ +. + +/** + * Database enrolment plugin. + * + * This plugin synchronises enrolment and roles with external database table. + * + * @package enrol_database + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Database enrolment plugin implementation. + * @author Petr Skoda - based on code by Martin Dougiamas, Martin Langhoff and others + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_database_plugin extends enrol_plugin { + /** + * Is it possible to delete enrol instance via standard UI? + * + * @param object $instance + * @return bool + */ + public function instance_deleteable($instance) { + if (!enrol_is_enabled('database')) { + return true; + } + if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) { + return true; + } + + //TODO: connect to external system and make sure no users are to be enrolled in this course + return false; + } + + /** + * Forces synchronisation of user enrolments with external database. + * + * @param object $user user record + * @return void + */ + public function sync_user_enrolments($user = NULL) { + + //TODO: full sync with external system is very expensive, it could cause big perf problems if we did that during each log-in, + // so do the sync only once in a while or rely on cron + } + + /** + * Forces synchronisation of all enrolments with external database. + * + * @return void + */ + public function sync_enrolments() { + global $CFG, $DB; + + // we do not create courses here intentionally because it requires full sync and is slow + if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) { + return; + } + + // we may need a lot of memory here + @set_time_limit(0); + @raise_memory_limit("512M"); + + $extdb = $this->db_init(); + + // second step is to sync instances and users + $table = $this->get_config('remoteenroltable'); + $coursefield = strtolower($this->get_config('remotecoursefield')); + $userfield = strtolower($this->get_config('remoteuserfield')); + $rolefield = strtolower($this->get_config('remoterolefield')); + $localrolefield = $this->get_config('localrolefield'); + $localuserfield = $this->get_config('localuserfield'); + $unenrolaction = $this->get_config('unenrolaction'); + + // create roles mapping + $allroles = get_all_roles(); + $defaultrole = $this->get_config('defaultrole'); + if (!isset($allroles[$defaultrole])) { + $defaultrole = 0; + } + $roles = array(); + foreach ($allroles as $role) { + $roles[$role->$localrolefield] = $role->id; + } + + // first find all existing courses with enrol instance + $localcoursefiled = $this->get_config('localcoursefield'); + $sql = "SELECT c.id, c.visible, c.$localcoursefiled AS mapping, e.id AS enrolid + FROM {course} c + JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')"; + $existing = array(); + $rs = $DB->get_recordset_sql($sql); // watch out for idnumber duplicates + foreach ($rs as $course) { + if (empty($course->mapping)) { + continue; + } + $existing[$course->mapping] = $course; + } + $rs->close(); + + // add necessary enrol instances that are not present yet; + $sql = $this->db_get_sql($table, array(), array($coursefield), true); + if ($rs = $extdb->Execute($sql)) { + if (!$rs->EOF) { + $sql = "SELECT c.id, c.visible + FROM {course} c + JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database') + WHERE c.$localcoursefiled = :mapping"; + $params = array(); + while ($mapping = $rs->FetchRow()) { + $mapping = reset($mapping); + $mapping = $this->db_decode($mapping); + if (!empty($mapping) and !isset($existing[$mapping])) { + $params['mapping'] = $mapping; + if ($course = $DB->get_record_sql($sql, $params, IGNORE_MULTIPLE)) { + $new = new object(); + $new->id = $course->id; + $new->visible = $course->visible; + $new->mapping = $mapping; + $new->enrolid = $this->add_instance($course); + $existing[$mapping] = $new; + } + } + } + } + $rs->Close(); + } else { + debugging('Error while communicating with external enrolment database'); + $extdb->Close(); + return; + } + + // sync enrolments + $ignorehidden = $this->get_config('ignorehiddencourses'); + $fields = array($userfield); + if ($rolefield) { + $fields[] = $rolefield; + } + foreach ($existing as $course) { + if ($ignorehidden and !$course->visible) { + continue; + } + if (!$instance = $DB->get_record('enrol', array('id'=>$course->enrolid))) { + continue; //weird + } + $context = get_context_instance(CONTEXT_COURSE, $course->id); + + // get current list of enrolled users with their roles + $current_roles = array(); + $current_status = array(); + $user_mapping = array(); + $sql = "SELECT u.$localuserfield AS mapping, u.id, ue.status, ue.userid, ra.roleid + FROM {user} u + JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid) + JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.itemid = ue.enrolid AND ra.component = 'enrol_database') + WHERE u.deleted = 0"; + $params = array('enrolid'=>$instance->id); + if ($localuserfield === 'username') { + $sql .= " AND u.mnethostid = :mnethostid"; + $params['mnethostid'] = $CFG->mnet_localhost_id; + } + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $ue) { + $current_roles[$ue->userid][$ue->roleid] = $ue->roleid; + $current_status[$ue->userid] = $ue->status; + $user_mapping[$ue->mapping] = $ue->userid; + } + $rs->close(); + + // get list of users that need to be enrolled and their roles + $requested_roles = array(); + $sql = $this->db_get_sql($table, array($coursefield=>$course->mapping), $fields); + if ($rs = $extdb->Execute($sql)) { + if (!$rs->EOF) { + if ($localuserfield === 'username') { + $usersearch = array('mnethostid'=>$CFG->mnet_localhost_id, 'deleted' =>0); + } + while ($fields = $rs->FetchRow()) { + $fields = array_change_key_case($fields, CASE_LOWER); + if (empty($fields[$userfield])) { + //user identification is mandatory! + } + $mapping = $fields[$userfield]; + if (!isset($user_mapping[$mapping])) { + $usersearch[$localuserfield] = $mapping; + if (!$user = $DB->get_record('user', $usersearch, 'id', IGNORE_MULTIPLE)) { + // user does not exist or was deleted + continue; + } + $user_mapping[$mapping] = $user->id; + $userid = $user->id; + } else { + $userid = $user_mapping[$mapping]; + } + if (empty($fields[$rolefield]) or !isset($roles[$fields[$rolefield]])) { + if (!$defaultrole) { + // role is mandatory + continue; + } + $roleid = $defaultrole; + } else { + $roleid = $roles[$fields[$rolefield]]; + } + + $requested_roles[$userid][$roleid] = $roleid; + } + } + $rs->Close(); + } else { + debugging('Error while communicating with external enrolment database'); + $extdb->Close(); + return; + } + unset($user_mapping); + + // enrol all users and sync roles + foreach ($requested_roles as $userid=>$roles) { + foreach ($roles as $roleid) { + if (empty($current_roles[$userid])) { + $this->enrol_user($instance, $userid, $roleid); + $current_roles[$userid][$roleid] = $roleid; + $current_status[$userid] = ENROL_USER_ACTIVE; + } + } + + // unassign removed roles + foreach($current_roles[$userid] as $cr) { + if (empty($roles[$cr])) { + role_unassign($cr, $userid, $context->id, 'enrol_database', $instance->id); + unset($current_roles[$userid][$cr]); + } + } + + // reenable enrolment when previously disable enrolment refreshed + if ($current_status[$userid] == ENROL_USER_SUSPENDED) { + $DB->set_field('user_enrolments', 'status', ENROL_USER_ACTIVE, array('enrolid'=>$instance->id, 'userid'=>$userid)); + } + } + + // deal with enrolments removed from external table + if ($unenrolaction == 0) { + // unenrol + if (!empty($requested_roles)) { + // we might get some error or connection problem, better not unenrol everybody + foreach ($current_status as $userid=>$status) { + if (isset($requested_roles[$userid])) { + continue; + } + $this->unenrol_user($instance, $userid); + } + } + + } else if ($unenrolaction == 1) { + // keep - only adding enrolments + + } else if ($unenrolaction == 2) { + // disable + foreach ($current_status as $userid=>$status) { + if (isset($requested_roles[$userid])) { + continue; + } + if ($status != ENROL_USER_SUSPENDED) { + $DB->set_field('user_enrolments', 'status', ENROL_USER_SUSPENDED, array('enrolid'=>$instance->id, 'userid'=>$userid)); + } + } + } + } + + // close db connection + $extdb->Close(); + } + + /** + * Performs a full sync with external database. + * + * First it creates new courses if necessary, then + * enrols and unenrols users. + * @return void + */ + public function sync_courses() { + global $CFG, $DB; + + // make sure we sync either enrolments or courses + if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or $this->get_config('newcoursetable') or $this->get_config('newcoursefullname') or $this->get_config('newcourseshortname')) { + return; + } + + // we may need a lot of memory here + @set_time_limit(0); + @raise_memory_limit("512M"); + + $extdb = $this->db_init(); + + // first create new courses + $table = $this->get_config('newcoursetable'); + $fullname = strtolower($this->get_config('newcoursefullname')); + $shortname = strtolower($this->get_config('newcourseshortname')); + $idnumber = strtolower($this->get_config('newcourseidnumber')); + $category = strtolower($this->get_config('newcoursecategory')); + + $fields = array($fullname, $shortname, $idnumber); + if ($category) { + $fields[] = $category; + } + if ($idnumber) { + $fields[] = $idnumber; + } + $sql = $this->db_get_sql($table, array(), $fields); + $createcourses = array(); + if ($rs = $extdb->Execute($sql)) { + if (!$rs->EOF) { + $courselist = array(); + while ($fields = $rs->FetchRow()) { + $fields = array_change_key_case($fields, CASE_LOWER); + if (empty($fields[$shortname]) or empty($fields[$fullname])) { + //invalid record - these two are mandatory + continue; + } + $fields = $this->db_decode($fields); + if ($DB->record_exists('course', array('shortname'=>$fields[$shortname]))) { + // already exists + continue; + } + if ($idnumber and $DB->record_exists('course', array('idnumber'=>$fields[$idnumber]))) { + // idnumber duplicates are not allowed + continue; + } + if ($category and !$DB->record_exists('course_categories', array('id'=>$fields[$category]))) { + // invalid category id, better to skip + continue; + } + $course = new object(); + $course->fullname = $fields[$fullname]; + $course->shortname = $fields[$shortname]; + $course->idnumber = $idnumber ? $fields[$idnumber] : NULL; + $course->category = $category ? $fields[$category] : NULL; + $createcourses[] = $course; + } + } + $rs->Close(); + } else { + debugging('Error while communicating with external enrolment database'); + $extdb->Close(); + return; + } + if ($createcourses) { + require_once("$CFG->dirroot/course/lib.php"); + + $template = $this->get_config('templatecourse'); + $defaultcategory = $this->get_config('defaultcategory'); + + if ($template) { + if ($template = $DB->get_record('course', array('shortname'=>$template))) { + unset($template->id); + unset($template->fullname); + unset($template->shortname); + unset($template->idnumber); + } else { + $template = new object(); + } + } else { + $template = new object(); + } + if (!$DB->record_exists('course_categories', array('id'=>$defaultcategory))) { + $categories = $DB->get_records('course_categories', array(), 'sortorder', 'id', 0, 1); + $first = reset($categories); + $defaultcategory = $first->id; + } + + foreach ($createcourses as $fields) { + $newcourse = clone($template); + $newcourse->fullname = $fields->fullname; + $newcourse->shortname = $fields->shortname; + $newcourse->idnumber = $fields->idnumber; + $newcourse->category = $fields->category ? $fields->category : $defaultcategory; + + create_course($newcourse); + } + + unset($createcourses); + unset($template); + } + + // close db connection + $extdb->Close(); + } + + protected function db_get_sql($table, array $conditions, array $fields, $distinct = false, $sort = "") { + $fields = $fields ? implode(',', $fields) : "*"; + $where = array(); + if ($conditions) { + foreach ($conditions as $key=>$value) { + $value = $this->db_encode($this->db_addslashes($value)); + + $where[] = "$key = '$value'"; + } + } + $where = $where ? "WHERE ".implode(" AND ", $where) : ""; + $sort = $sort ? "ORDER BY $sort" : ""; + $distinct = $distinct ? "DISTINCT" : ""; + $sql = "SELECT $distinct $fields + FROM $table + $where + $sort"; + + return $sql; + } + + protected function db_init() { + global $CFG; + + require_once($CFG->libdir.'/adodb/adodb.inc.php'); + + // Connect to the external database (forcing new connection) + $extdb = ADONewConnection($this->get_config('dbtype')); + if ($this->get_config('debugdb')) { + $extdb->debug = true; + ob_start(); //start output buffer to allow later use of the page headers + } + + $extdb->Connect($this->get_config('dbhost'), $this->get_config('dbuser'), $this->get_config('dbpass'), $this->get_config('dbname'), true); + $extdb->SetFetchMode(ADODB_FETCH_ASSOC); + if ($this->get_config('dbsetupsql')) { + $extdb->Execute($this->get_config('dbsetupsql')); + } + return $extdb; + } + + protected function db_addslashes($text) { + // using custom made function for now + if ($this->get_config('dbsybasequoting')) { + $text = str_replace('\\', '\\\\', $text); + $text = str_replace(array('\'', '"', "\0"), array('\\\'', '\\"', '\\0'), $text); + } else { + $text = str_replace("'", "''", $text); + } + return $text; + } + + protected function db_encode($text) { + $dbenc = $this->get_config('dbencoding'); + if (empty($dbenc) or $dbenc == 'utf-8') { + return $text; + } + if (is_array($text)) { + foreach($text as $k=>$value) { + $text[$k] = $this->db_encode($value); + } + return $text; + } else { + return textlib_get_instance()->convert($text, 'utf-8', $dbenc); + } + } + + protected function db_decode($text) { + $dbenc = $this->get_config('dbencoding'); + if (empty($dbenc) or $dbenc == 'utf-8') { + return $text; + } + if (is_array($text)) { + foreach($text as $k=>$value) { + $text[$k] = $this->db_decode($value); + } + return $text; + } else { + return textlib_get_instance()->convert($text, $dbenc, 'utf-8'); + } + } +} + diff --git a/enrol/database/settings.php b/enrol/database/settings.php new file mode 100644 index 00000000000..f776956d9e3 --- /dev/null +++ b/enrol/database/settings.php @@ -0,0 +1,115 @@ +. + +/** + * Database enrolment plugin settings and presets. + * + * @package enrol_database + * @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_database_settings', '', get_string('pluginname_desc', 'enrol_database'))); + + $settings->add(new admin_setting_heading('enrol_database_exdbheader', get_string('settingsheaderdb', 'enrol_database'), '')); + + $options = array('', "access","ado_access", "ado", "ado_mssql", "borland_ibase", "csv", "db2", "fbsql", "firebird", "ibase", "informix72", "informix", "mssql", "mssql_n", "mysql", "mysqli", "mysqlt", "oci805", "oci8", "oci8po", "odbc", "odbc_mssql", "odbc_oracle", "oracle", "postgres64", "postgres7", "postgres", "proxy", "sqlanywhere", "sybase", "vfp"); + $options = array_combine($options, $options); + $settings->add(new admin_setting_configselect('enrol_database/dbtype', get_string('dbtype', 'enrol_database'), get_string('dbtype_desc', 'enrol_database'), '', $options)); + + $settings->add(new admin_setting_configtext('enrol_database/dbhost', get_string('dbhost', 'enrol_database'), get_string('dbhost_desc', 'enrol_database'), 'localhost')); + + $settings->add(new admin_setting_configtext('enrol_database/dbuser', get_string('dbuser', 'enrol_database'), '', '')); + + $settings->add(new admin_setting_configpasswordunmask('enrol_database/dbpass', get_string('dbpass', 'enrol_database'), '', '')); + + $settings->add(new admin_setting_configtext('enrol_database/dbname', get_string('dbname', 'enrol_database'), '', '')); + + $settings->add(new admin_setting_configtext('enrol_database/dbencoding', get_string('dbencoding', 'enrol_database'), '', 'utf-8')); + + $settings->add(new admin_setting_configtext('enrol_database/dbsetupsql', get_string('dbsetupsql', 'enrol_database'), get_string('dbsetupsql_desc', 'enrol_database'), '')); + + $settings->add(new admin_setting_configcheckbox('enrol_database/dbsybasequoting', get_string('dbsybasequoting', 'enrol_database'), get_string('dbsybasequoting_desc', 'enrol_database'), 0)); + + $settings->add(new admin_setting_configcheckbox('enrol_database/debugdb', get_string('debugdb', 'enrol_database'), get_string('debugdb_desc', 'enrol_database'), 0)); + + + + $settings->add(new admin_setting_heading('enrol_database_localheader', get_string('settingsheaderlocal', 'enrol_database'), '')); + + $options = array('id'=>'id', 'idnumber'=>'idnumber', 'shortname'=>'shortname'); + $settings->add(new admin_setting_configselect('enrol_database/localcoursefield', get_string('localcoursefield', 'enrol_database'), '', 'idnumber', $options)); + + $options = array('id'=>'id', 'idnumber'=>'idnumber', 'email'=>'email', 'username'=>'username'); // only local users if username selected, no mnet users! + $settings->add(new admin_setting_configselect('enrol_database/localuserfield', get_string('localuserfield', 'enrol_database'), '', 'idnumber', $options)); + + $options = array('id'=>'id', 'shortname'=>'shortname', 'fullname'=>'fullname'); + $settings->add(new admin_setting_configselect('enrol_database/localrolefield', get_string('localrolefield', 'enrol_database'), '', 'shortname', $options)); + + + + $settings->add(new admin_setting_heading('enrol_database_remoteheader', get_string('settingsheaderremote', 'enrol_database'), '')); + + $settings->add(new admin_setting_configtext('enrol_database/remoteenroltable', get_string('remoteenroltable', 'enrol_database'), get_string('remoteenroltable_desc', 'enrol_database'), '')); + + $settings->add(new admin_setting_configtext('enrol_database/remotecoursefield', get_string('remotecoursefield', 'enrol_database'), get_string('remotecoursefield_desc', 'enrol_database'), '')); + + $settings->add(new admin_setting_configtext('enrol_database/remoteuserfield', get_string('remoteuserfield', 'enrol_database'), get_string('remoteuserfield_desc', 'enrol_database'), '')); + + $settings->add(new admin_setting_configtext('enrol_database/remoterolefield', get_string('remoterolefield', 'enrol_database'), get_string('remoterolefield_desc', 'enrol_database'), '')); + + if (!during_initial_install()) { + $options = get_default_enrol_roles(get_context_instance(CONTEXT_SYSTEM)); + $student = get_archetype_roles('student'); + $student = reset($student); + $settings->add(new admin_setting_configselect('enrol_database/defaultrole', get_string('defaultrole', 'enrol_database'), get_string('defaultrole_desc', 'enrol_database'), $student->id, $options)); + } + + $settings->add(new admin_setting_configcheckbox('enrol_database/ignorehiddencourses', get_string('ignorehiddencourses', 'enrol_database'), get_string('ignorehiddencourses_desc', 'enrol_database'), 0)); + + $options = array(0=>get_string('unenrolactionunenrol', 'enrol_database'), 1=>get_string('unenrolactionkeep', 'enrol_database'), 2=>get_string('unenrolactiondisable', 'enrol_database')); + $settings->add(new admin_setting_configselect('enrol_database/unenrolaction', get_string('unenrolaction', 'enrol_database'), get_string('unenrolaction_desc', 'enrol_database'), 0, $options)); + + + + $settings->add(new admin_setting_heading('enrol_database_newcoursesheader', get_string('settingsheadernewcourses', 'enrol_database'), '')); + + $settings->add(new admin_setting_configtext('enrol_database/newcoursetable', get_string('newcoursetable', 'enrol_database'), get_string('newcoursetable_desc', 'enrol_database'), '')); + + $settings->add(new admin_setting_configtext('enrol_database/newcoursefullname', get_string('newcoursefullname', 'enrol_database'), '', 'fullname')); + + $settings->add(new admin_setting_configtext('enrol_database/newcourseshortname', get_string('newcourseshortname', 'enrol_database'), '', 'shortname')); + + $settings->add(new admin_setting_configtext('enrol_database/newcourseidnumber', get_string('newcourseidnumber', 'enrol_database'), '', 'idnumber')); + + $settings->add(new admin_setting_configtext('enrol_database/newcoursecategory', get_string('newcoursecategory', 'enrol_database'), '', '')); + + if (!during_initial_install()) { + $options = array(); + $parentlist = array(); + make_categories_list($options, $parentlist); + $settings->add(new admin_setting_configselect('enrol_database/defaultcategory', get_string('defaultcategory', 'enrol_database'), get_string('defaultcategory_desc', 'enrol_database'), 1, $options)); + unset($parentlist); + } + + $settings->add(new admin_setting_configtext('enrol_database/templatecourse', get_string('templatecourse', 'enrol_database'), get_string('templatecourse_desc', 'enrol_database'), '')); +} diff --git a/enrol/database/version.php b/enrol/database/version.php new file mode 100644 index 00000000000..1b8e1c60a5f --- /dev/null +++ b/enrol/database/version.php @@ -0,0 +1,27 @@ +. + +/** + * Database enrolment plugin version specification. + * + * @package enrol_database + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$plugin->version = 2010061500; +//TODO: should we add cron sync? \ No newline at end of file diff --git a/enrol/enrol.class.php b/enrol/enrol.class.php deleted file mode 100644 index 8ff8afd6050..00000000000 --- a/enrol/enrol.class.php +++ /dev/null @@ -1,22 +0,0 @@ -enrol; - } - if (file_exists("$CFG->dirroot/enrol/$enrol/enrol.php")) { - require_once("$CFG->dirroot/enrol/$enrol/enrol.php"); - $class = "enrolment_plugin_$enrol"; - return new $class; - } else { - error_log("$CFG->dirroot/enrol/$enrol/enrol.php does not exist"); - echo $OUTPUT->notification("Enrolment file $enrol/enrol.php does not exist"); - } - } -} diff --git a/enrol/externallib.php b/enrol/externallib.php index c48239e6f54..85cbf80a69f 100644 --- a/enrol/externallib.php +++ b/enrol/externallib.php @@ -16,35 +16,119 @@ // along with Moodle. If not, see . /** - * External enrol API + * External course participation api. * - * @package moodlecore - * @subpackage webservice + * This api is mostly read only, the actual enrol and unenrol + * support is in each enrol plugin. + * + * @package core + * @subpackage enrol * @copyright 2009 Moodle Pty Ltd (http://moodle.com) * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +defined('MOODLE_INTERNAL') || die; + require_once("$CFG->libdir/externallib.php"); + class moodle_enrol_external extends external_api { /** * Returns description of method parameters * @return external_function_parameters */ - public static function role_assign_parameters() { - global $CFG; - + public static function get_enrolled_users() { return new external_function_parameters( array( - 'enrolments' => new external_multiple_structure( + 'courseid' => new external_value(PARAM_INT, 'Course id'), + 'withcapability' => new external_value(PARAM_CAPABILITY, 'User should have this capability'), + 'groupid' => new external_value(PARAM_INT, 'Group id, null means all groups'), + 'activeonly' => new external_value(PARAM_INT, 'True means only active, false means all participants'), + ) + ); + } + + /** + * Get list of course participants. + * + * @param int $courseid + * @param text $withcapability + * @param int $groupid + * @param bool $onlyactive + * @return array of course participants + */ + public static function get_enrolled_users($courseid, $withcapability, $groupid, $onlyactive) { + global $DB; + + // Do basic automatic PARAM checks on incoming data, using params description + // If any problems are found then exceptions are thrown with helpful error messages + $params = self::validate_parameters(self::get_enrolled_users(), array('courseid'=>$courseid, 'withcapability'=>$withcapability, 'groupid'=>$groupid, 'onlyactive'=>$onlyactive)); + + $coursecontext = get_context_instance(CONTEXT_COURSE, $params['courseid']); + if ($courseid == SITEID) { + $systemcontext = get_context_instance(CONTEXT_SYSTEM); + } else { + $context = $coursecontext; + } + + self::validate_context($context); + + if ($courseid == SITEID) { + require_capability('moodle/site:viewparticipants', $context); + } else { + require_capability('moodle/course:viewparticipants', $context); + } + + if ($withcapability) { + require_capability('moodle/role:review', $coursecontext); + } + if ($groupid) { + if (groups_is_member($groupid)) { + require_capability('moodle/site:accessallgroups', $coursecontext); + } + } + if ($activeonly) { + require_capability('moodle/course:enrolreview', $coursecontext); + } + + list($sql, $params) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive); + $sql = "SELECT e.courseid, ue.userid + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid) + WHERE e.courseid = :courseid AND ue.userid IN ($sql)"; + $params['courseid'] = $courseid; + + return $DB->get_records_sql($sql, $params); + } + + /** + * Returns description of method result value + * @return external_description + */ + public static function get_enrolled_users_returns() { + new external_single_structure( + array( + 'courseid' => new external_value(PARAM_INT, 'id of course'), + 'userid' => new external_value(PARAM_INT, 'id of user'), + ) + ); + } + + + /** + * Returns description of method parameters + * @return external_function_parameters + */ + public static function role_assign_parameters() { + return new external_function_parameters( + array( + 'assignments' => new external_multiple_structure( new external_single_structure( array( 'roleid' => new external_value(PARAM_INT, 'Role to assign to the user'), 'userid' => new external_value(PARAM_INT, 'The user that is going to be assigned'), - 'contextid' => new external_value(PARAM_INT, 'The context to assign the user into '), - 'timestart' => new external_value(PARAM_INT, 'A valid and unique email address', VALUE_DEFAULT, 0), - 'timeend' => new external_value(PARAM_INT, 'Auth plugins include manual, ldap, imap, etc', VALUE_DEFAULT, 0) + 'contextid' => new external_value(PARAM_INT, 'The context to assign the user role in'), ) ) ) @@ -53,36 +137,30 @@ class moodle_enrol_external extends external_api { } /** - * Assign roles to users + * Manual role assignments to users * - * @param array $enrolment An array of enrolment + * @param array $assignment An array of manual role assignment * @return null */ - public static function role_assign($enrolments) { - global $CFG, $DB; + public static function role_assign($assignments) { + global $DB; // Do basic automatic PARAM checks on incoming data, using params description // If any problems are found then exceptions are thrown with helpful error messages - $params = self::validate_parameters(self::role_assign_parameters(), array('enrolments'=>$enrolments)); + $params = self::validate_parameters(self::role_assign_parameters(), array('assignments'=>$assignments)); $transaction = $DB->start_delegated_transaction(); - $success = true; - - foreach ($params['enrolments'] as $enrolment) { + foreach ($params['assignments'] as $assignment) { // Ensure the current user is allowed to run this function in the enrolment context - $context = get_context_instance_by_id($enrolment['contextid']); + $context = get_context_instance_by_id($assignment['contextid']); self::validate_context($context); require_capability('moodle/role:assign', $context); - if(!role_assign($enrolment['roleid'], $enrolment['userid'], null, $enrolment['contextid'], $enrolment['timestart'], $enrolment['timeend'])) { - $success = false; - } + role_assign($assignment['roleid'], $assignment['userid'], $assignment['contextid']); } $transaction->allow_commit(); - - return $success; } /** @@ -90,7 +168,7 @@ class moodle_enrol_external extends external_api { * @return external_description */ public static function role_assign_returns() { - return new external_value(PARAM_BOOL, 'If all assignement succeed returns true'); + return null; } @@ -101,50 +179,44 @@ class moodle_enrol_external extends external_api { public static function role_unassign_parameters() { return new external_function_parameters( array( - 'unenrolments' => new external_multiple_structure( + 'unassignments' => new external_multiple_structure( new external_single_structure( array( 'roleid' => new external_value(PARAM_INT, 'Role to assign to the user'), 'userid' => new external_value(PARAM_INT, 'The user that is going to be assigned'), - 'contextid' => new external_value(PARAM_INT, 'The context to assign the user into '), - ) + 'contextid' => new external_value(PARAM_INT, 'The context to unassign the user role from'), + ) ) + ) ) - ) - ); + ); } /** - * Unassign roles to users + * Unassign roles from users * - * @param array $unenrolment An array of unenrolment + * @param array $unassignment An array of unassignment * @return null */ - public static function role_unassign($unenrolments) { - global $CFG, $DB; + public static function role_unassign($unassignments) { + global $DB; // Do basic automatic PARAM checks on incoming data, using params description // If any problems are found then exceptions are thrown with helpful error messages - $params = self::validate_parameters(self::role_unassign_parameters(), array('unenrolments'=>$unenrolments)); + $params = self::validate_parameters(self::role_unassign_parameters(), array('unassignments'=>$unassignments)); $transaction = $DB->start_delegated_transaction(); - $success = true; - - foreach ($params['unenrolments'] as $unenrolment) { - // Ensure the current user is allowed to run this function in the unenrolment context - $context = get_context_instance_by_id($unenrolment['contextid']); + foreach ($params['unassignments'] as $unassignment) { + // Ensure the current user is allowed to run this function in the unassignment context + $context = get_context_instance_by_id($unassignment['contextid']); self::validate_context($context); require_capability('moodle/role:assign', $context); - if (!role_unassign($unenrolment['roleid'], $unenrolment['userid'], null, $unenrolment['contextid'])) { - $success = false; - } + role_unassign($unassignment['roleid'], $unassignment['userid'], $unassignment['contextid']); } $transaction->allow_commit(); - - return $success; } /** @@ -152,7 +224,6 @@ class moodle_enrol_external extends external_api { * @return external_description */ public static function role_unassign_returns() { - return new external_value(PARAM_BOOL, 'If all unassignement succeed returns true'); + return null; } - } diff --git a/enrol/flatfile/enrol.php b/enrol/flatfile/enrol.php index e6a71073e94..229162484b0 100644 --- a/enrol/flatfile/enrol.php +++ b/enrol/flatfile/enrol.php @@ -187,9 +187,10 @@ function get_access_icons($course) { $context = get_context_instance(CONTEXT_COURSE, $course->id); if ($fields[0] == 'add') { - role_assign($roleid, $user->id, null, $context->id, $fields[4], $fields[5], 0, 'flatfile'); + // TODO: real enrol, and maybe manual + role_assign($roleid, $user->id, $context->id, 'enrol_flatfile'); } else { - role_unassign($roleid, $user->id, null, $context->id); + role_unassign($roleid, $user->id, $context->id); } diff --git a/enrol/guest/addinstance.php b/enrol/guest/addinstance.php new file mode 100644 index 00000000000..92f77c2726e --- /dev/null +++ b/enrol/guest/addinstance.php @@ -0,0 +1,43 @@ +. + +/** + * Adds new instance of enrol_guest to specified course. + * + * @package enrol_guest + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../config.php'); + +$id = required_param('id', PARAM_INT); // course id + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +require_login($course); +require_capability('moodle/course:enrolconfig', $context); +require_sesskey(); + +$enrol = enrol_get_plugin('guest'); + +if ($enrol->get_candidate_link($course->id)) { + $enrol->add_default_instance($course); +} + +redirect(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); diff --git a/enrol/guest/db/access.php b/enrol/guest/db/access.php new file mode 100644 index 00000000000..81a4fb27761 --- /dev/null +++ b/enrol/guest/db/access.php @@ -0,0 +1,39 @@ +. + +/** + * Capabilities for guest access plugin. + * + * @package enrol_guest + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$capabilities = array( + + 'enrol/guest:config' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'manager' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + ) + ), + +); + + diff --git a/enrol/guest/lang/en/enrol_guest.php b/enrol/guest/lang/en/enrol_guest.php new file mode 100644 index 00000000000..4643cb0c9d9 --- /dev/null +++ b/enrol/guest/lang/en/enrol_guest.php @@ -0,0 +1,40 @@ +. + +/** + * Strings for component 'enrol_guest', language 'en', branch 'MOODLE_20_STABLE' + * + * @package enrol_guest + * @copyright 2010 onwards Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['guest:config'] = 'Configure guest access instances'; +$string['password'] = 'Password'; +$string['passwordinvalid'] = 'Incorrect access password, please try again'; +$string['passwordinvalidhint'] = 'That access password was incorrect, please try again
+(Here\'s a hint - it starts with \'{$a}\')'; +$string['pluginname'] = 'Guest access'; +$string['pluginname_desc'] = 'Guest access plugin is only granting temporary access to courses, it is not actually enrolling users.'; +$string['requirepassword'] = 'Require guest access passsword'; +$string['requirepassword_desc'] = 'Require access password in new courses and prevent removing of access password from existing courses.'; +$string['showhint'] = 'Show hint'; +$string['showhint_desc'] = 'Show first letter of the guest access password.'; +$string['status'] = 'Allow guest access'; +$string['status_desc'] = 'Allow temporary guest access by default.'; +$string['usepasswordpolicy'] = 'Use password policy'; +$string['usepasswordpolicy_desc'] = 'Use standard password policy for guest access passwords.'; diff --git a/enrol/guest/lib.php b/enrol/guest/lib.php new file mode 100644 index 00000000000..6d832911be9 --- /dev/null +++ b/enrol/guest/lib.php @@ -0,0 +1,291 @@ +. + +/** + * Guest access plugin. + * + * This plugin does not add any entries into the user_enrolments table, + * the access control is granted on the fly via the tricks in require_login(). + * + * @package enrol_guest + * @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; + +class enrol_guest_plugin extends enrol_plugin { + + public function enrol_user(stdClass $instance, $userid, $roleid = null, $timestart = 0, $timeend = 0) { + // no real enrolments here! + return; + } + + public function unenrol_user(stdClass $instance, $userid) { + // nothing to do, we never enrol here! + return; + } + + /** + * Attempt to automatically gain temporary guest access to course, + * calling code has to make sure the plugin and instance are active. + * + * @param stdClass $instance course enrol instance + * @param stdClass $user record + * @return bool|int false means no guest access, integer means end of cached time + */ + public function try_guestaccess(stdClass $instance) { + global $USER, $CFG; + + if (empty($instance->password)) { + // Temporarily assign them some guest role for this context + $context = get_context_instance(CONTEXT_COURSE, $instance->courseid); + $USER->access = load_temp_role($context, $CFG->guestroleid, $USER->access); + return ENROL_REQUIRE_LOGIN_CACHE_PERIOD; + } + + return false; + } + + /** + * 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_candidate_link($courseid) { + global $DB; + + if (!has_capability('moodle/course:enrolconfig', get_context_instance(CONTEXT_COURSE, $courseid, MUST_EXIST))) { + return NULL; + } + + if ($DB->record_exists('enrol', array('courseid'=>$courseid, 'enrol'=>'guest'))) { + return NULL; + } + + return new moodle_url('/enrol/guest/addinstance.php', array('sesskey'=>sesskey(), 'id'=>$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; + + if (empty($instance->password)) { + return null; + } + + require_once("$CFG->dirroot/enrol/guest/locallib.php"); + $form = new enrol_guest_enrol_form(NULL, $instance); + $instanceid = optional_param('instance', 0, PARAM_INT); + + if ($instance->id == $instanceid) { + if ($data = $form->get_data()) { + // set up primitive require_login() caching + unset($USER->enrol['enrolled'][$instance->courseid]); + $USER->enrol['tempguest'][$instance->courseid] = time() + 60*60*8; // 8 hours access before asking for pw again + + // add guest role + $context = get_context_instance(CONTEXT_COURSE, $instance->courseid); + $USER->access = load_temp_role($context, $CFG->guestroleid, $USER->access); + + // go to the originally requested page + if (!empty($SESSION->wantsurl)) { + $destination = $SESSION->wantsurl; + unset($SESSION->wantsurl); + } else { + $destination = "$CFG->wwwroot/course/view.php?id=$instance->courseid"; + } + redirect($destination); + } + } + + ob_start(); + $form->display(); + $output = ob_get_clean(); + + return $OUTPUT->box($output, 'generalbox'); + } + + /** + * Adds enrol instance UI to course edit form + * + * @param object $instance enrol instance or null if does not exist yet + * @param MoodleQuickForm $mform + * @param object $data + * @param object $context context of existing course or parent category if course does not exist + * @return void + */ + public function course_edit_form($instance, MoodleQuickForm $mform, $data, $context) { + + $i = isset($instance->id) ? $instance->id : 0; + $plugin = enrol_get_plugin('guest'); + $header = $plugin->get_instance_name($instance); + $config = has_capability('enrol/guest:config', $context); + + $mform->addElement('header', 'enrol_guest_header_'.$i, $header); + + + $options = array(ENROL_INSTANCE_ENABLED => get_string('yes'), + ENROL_INSTANCE_DISABLED => get_string('no')); + $mform->addElement('select', 'enrol_guest_status_'.$i, get_string('status', 'enrol_guest'), $options); + $mform->setDefault('enrol_guest_status_'.$i, $this->get_config('status')); + $mform->setAdvanced('enrol_guest_status_'.$i, $this->get_config('status_adv')); + if (!$config) { + $mform->hardFreeze('enrol_guest_status_'.$i); + } + + $mform->addElement('passwordunmask', 'enrol_guest_password_'.$i, get_string('password', 'enrol_guest')); + if (!$config) { + $mform->hardFreeze('enrol_guest_password_'.$i); + } else { + $mform->disabledIf('enrol_guest_password_'.$i, 'enrol_guest_status_'.$i, 'noteq', ENROL_INSTANCE_ENABLED); + } + + + // now add all values from enrol table + if ($instance) { + foreach($instance as $key=>$val) { + $data->{'enrol_guest_'.$key.'_'.$i} = $val; + } + } + } + + /** + * Validates course edit form data + * + * @param object $instance enrol instance or null if does not exist yet + * @param array $data + * @param object $context context of existing course or parent category if course does not exist + * @return array errors array + */ + public function course_edit_validation($instance, array $data, $context) { + $errors = array(); + + if (!has_capability('enrol/guest:config', $context)) { + // we are going to ignore the data later anyway, they would nto be able to fix the form anyway + return $errors; + } + + $i = isset($instance->id) ? $instance->id : 0; + + $password = empty($data['enrol_guest_password_'.$i]) ? '' : $data['enrol_guest_password_'.$i]; + $checkpassword = false; + + if ($instance) { + if ($data['enrol_guest_status_'.$i] == ENROL_INSTANCE_ENABLED) { + if ($instance->password !== $password) { + $checkpassword = true; + } + } + } else { + if ($data['enrol_guest_status_'.$i] == ENROL_INSTANCE_ENABLED) { + $checkpassword = true; + } + } + + if ($checkpassword) { + $require = $this->get_config('requirepassword'); + $policy = $this->get_config('usepasswordpolicy'); + if ($require and empty($password)) { + $errors['enrol_guest_password_'.$i] = get_string('required'); + } else if ($policy) { + $errmsg = '';//prevent eclipse warning + if (!check_password_policy($password, $errmsg)) { + $errors['enrol_guest_password_'.$i] = $errmsg; + } + } + } + + return $errors; + } + + /** + * Called after updating/inserting course. + * + * @param bool $inserted true if course just inserted + * @param object $course + * @param object $data form data + * @return void + */ + public function course_updated($inserted, $course, $data) { + global $DB; + + $context = get_context_instance(CONTEXT_COURSE, $course->id); + + if (has_capability('enrol/guest:config', $context)) { + if ($inserted) { + if (isset($data->enrol_guest_status_0)) { + $fields = array('status'=>$data->enrol_guest_status_0); + if ($fields['status'] == ENROL_INSTANCE_ENABLED) { + $fields['password'] = $data->enrol_guest_password_0; + } else { + if ($this->get_config('requirepassword')) { + $fields['password'] = generate_password(20); + } + } + $this->add_instance($course, $fields); + } + } else { + $instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'guest')); + foreach ($instances as $instance) { + $i = $instance->id; + + if (isset($data->{'enrol_guest_status_'.$i})) { + $instance->status = $data->{'enrol_guest_status_'.$i}; + $instance->timemodified = time(); + if ($instance->status == ENROL_INSTANCE_ENABLED) { + $instance->password = $data->{'enrol_guest_password_'.$i}; + } + $DB->update_record('enrol', $instance); + } + } + } + + } else { + if ($inserted) { + if ($this->get_config('defaultenrol')) { + $this->add_default_instance($course); + } + } else { + // bad luck, user can not change anything + } + } + } + + /** + * Add new instance of enrol plugin with default settings. + * @param object $course + * @return int id of new instance + */ + public function add_default_instance($course) { + $fields = array('status'=>$this->get_config('status')); + + if ($this->get_config('requirepassword')) { + $fields['password'] = generate_password(20); + } + + return $this->add_instance($course, $fields); + } + +} + diff --git a/enrol/guest/locallib.php b/enrol/guest/locallib.php new file mode 100644 index 00000000000..ab9f07b9946 --- /dev/null +++ b/enrol/guest/locallib.php @@ -0,0 +1,76 @@ +. + +/** + * Guest access plugin implementation. + * + * @package enrol_guest + * @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_guest_enrol_form extends moodleform { + protected $instance; + + public function definition() { + $mform = $this->_form; + $instance = $this->_customdata; + $this->instance = $instance; + $plugin = enrol_get_plugin('guest'); + + $heading = $plugin->get_instance_name($instance); + $mform->addElement('header', 'guestheader', $heading); + + $mform->addElement('passwordunmask', 'guestpassword', get_string('password', 'enrol_guest')); + + $this->add_action_buttons(false, get_string('submit')); + + $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 ($instance->password) { + if ($data['guestpassword'] !== $instance->password) { + $plugin = enrol_get_plugin('guest'); + if ($plugin->get_config('showhint')) { + $textlib = textlib_get_instance(); + $hint = $textlib->substr($instance->password, 0, 1); + $errors['guestpassword'] = get_string('passwordinvalidhint', 'enrol_guest', $hint); + } else { + $errors['guestpassword'] = get_string('passwordinvalid', 'enrol_guest'); + } + } + } + + return $errors; + } +} \ No newline at end of file diff --git a/enrol/guest/settings.php b/enrol/guest/settings.php new file mode 100644 index 00000000000..a161c578753 --- /dev/null +++ b/enrol/guest/settings.php @@ -0,0 +1,56 @@ +. + +/** + * Guest access plugin settings and presets. + * + * @package enrol_guest + * @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_guest_settings', '', get_string('pluginname_desc', 'enrol_guest'))); + + $settings->add(new admin_setting_configcheckbox('enrol_guest/requirepassword', + get_string('requirepassword', 'enrol_guest'), get_string('requirepassword_desc', 'enrol_guest'), 0)); + + $settings->add(new admin_setting_configcheckbox('enrol_guest/usepasswordpolicy', + get_string('usepasswordpolicy', 'enrol_guest'), get_string('usepasswordpolicy_desc', 'enrol_guest'), 0)); + + $settings->add(new admin_setting_configcheckbox('enrol_guest/showhint', + get_string('showhint', 'enrol_guest'), get_string('showhint_desc', 'enrol_guest'), 0)); + + + //--- enrol instance defaults ---------------------------------------------------------------------------- + $settings->add(new admin_setting_heading('enrol_guest_defaults', + get_string('enrolinstancedefaults', 'admin'), get_string('enrolinstancedefaults_desc', 'admin'))); + + $settings->add(new admin_setting_configcheckbox('enrol_guest/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_with_advanced('enrol_guest/status', + get_string('status', 'enrol_guest'), get_string('status_desc', 'enrol_guest'), + array('value'=>ENROL_INSTANCE_DISABLED, 'adv'=>false), $options)); +} + diff --git a/enrol/guest/version.php b/enrol/guest/version.php new file mode 100644 index 00000000000..4c5241d77d4 --- /dev/null +++ b/enrol/guest/version.php @@ -0,0 +1,26 @@ +. + +/** + * Guest access plugin version specification. + * + * @package enrol_guest + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$plugin->version = 2010061500; diff --git a/enrol/imsenterprise/enrol.php b/enrol/imsenterprise/enrol.php index 316c77444b6..1575f28905f 100644 --- a/enrol/imsenterprise/enrol.php +++ b/enrol/imsenterprise/enrol.php @@ -761,7 +761,8 @@ function process_membership_tag($tagcontents){ // Enrol unsing the generic role_assign() function - if ((!role_assign($moodleroleid, $memberstoreobj->userid, 0, $rolecontext, $timeframe->begin, $timeframe->end, 0, 'imsenterprise')) && (trim($memberstoreobj->userid)!='')) { + //TODO: some real enrolment here + if ((!role_assign($moodleroleid, $memberstoreobj->userid, $rolecontext, 'enrol_imsenterprise')) && (trim($memberstoreobj->userid)!='')) { $this->log_line("Error enrolling user #$memberstoreobj->userid ($member->idnumber) to role $member->roletype in course $memberstoreobj->course"); }else{ $this->log_line("Enrolled user #$memberstoreobj->userid ($member->idnumber) to role $member->roletype in course $memberstoreobj->course"); @@ -798,12 +799,9 @@ function process_membership_tag($tagcontents){ }elseif($CFG->enrol_imsunenrol){ // Unenrol - if (! role_unassign($moodleroleid, $memberstoreobj->userid, 0, $rolecontext, 'imsenterprise')) { - $this->log_line("Error unenrolling $memberstoreobj->userid from role $moodleroleid in course"); - }else{ - $membersuntally++; - $this->log_line("Unenrolled $member->idnumber from role $moodleroleid in course"); - } + role_unassign($moodleroleid, $memberstoreobj->userid, 0, $rolecontext, 'imsenterprise'); + $membersuntally++; + $this->log_line("Unenrolled $member->idnumber from role $moodleroleid in course"); } } diff --git a/enrol/index.html b/enrol/index.html deleted file mode 100644 index 8b137891791..00000000000 --- a/enrol/index.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/enrol/index.php b/enrol/index.php new file mode 100644 index 00000000000..d8200cd2e77 --- /dev/null +++ b/enrol/index.php @@ -0,0 +1,99 @@ +. + +/** + * This page shows all course enrolment options for current user. + * + * @package core + * @subpackage course + * @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("$CFG->libdir/formslib.php"); + +$id = required_param('id', PARAM_INT); + +if (!isloggedin()) { + // do not use require_login here because we are usually coming from it, + // it would also mess up the SESSION->wantsurl + redirect(get_login_url()); +} + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +// Everybody is enrolled on the frontpage +if ($course->id == SITEID) { + redirect("$CFG->wwwroot/"); +} + +$PAGE->set_url('/enrol/index.php', array('id'=>$course->id)); + +// do not allow enrols when in login-as session +if (session_is_loggedinas() and $USER->loginascontext->contextlevel == CONTEXT_COURSE) { + print_error('loginasnoenrol', '', $CFG->wwwroot.'/course/view.php?id='.$USER->loginascontext->instanceid); +} + +// get all enrol forms available in this course +$enrols = enrol_get_plugins(true); +$enrolinstances = enrol_get_instances($course->id, true); +$forms = array(); +foreach($enrolinstances as $instance) { + if (!isset($enrols[$instance->enrol])) { + continue; + } + $form = $enrols[$instance->enrol]->enrol_page_hook($instance); + if ($form) { + $forms[$instance->id] = $form; + } +} + +// Check if user already enrolled +if (is_enrolled($context, $USER, '', true)) { + if (!empty($SESSION->wantsurl)) { + $destination = $SESSION->wantsurl; + unset($SESSION->wantsurl); + } else { + $destination = "$CFG->wwwroot/course/view.php?id=$course->id"; + } + redirect($destination); // Bye! +} + +$PAGE->set_title($course->shortname); +$PAGE->set_heading($course->fullname); +$PAGE->navbar->add($course->fullname); + + +echo $OUTPUT->header(); + +//TODO: find if future enrolments present and display some info + +foreach ($forms as $form) { + echo $form; +} + +if (!$forms) { + if (isguestuser()) { + notice(get_string('noguestaccess', 'enrol'), get_login_url()); + } else { + notice(get_string('notenrollable', 'enrol'), "$CFG->wwwroot/index.php"); + } +} + +echo $OUTPUT->footer(); diff --git a/enrol/instances.php b/enrol/instances.php new file mode 100644 index 00000000000..07844233935 --- /dev/null +++ b/enrol/instances.php @@ -0,0 +1,237 @@ +. + +/** + * Main course enrolment management UI. + * + * @package core + * @subpackage enrol + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../config.php'); + +$id = required_param('id', PARAM_INT); // course id +$action = optional_param('action', '', PARAM_ACTION); +$instanceid = optional_param('instance', 0, PARAM_INT); +$confirm = optional_param('confirm', 0, PARAM_BOOL); + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +if ($course->id == SITEID) { + redirect("$CFG->wwwroot/"); +} + +require_login($course); +require_capability('moodle/course:enrolreview', $context); + +$canconfig = has_capability('moodle/course:enrolconfig', $context); + +$PAGE->set_url('/enrol/instances.php', array('id'=>$course->id)); +$PAGE->set_pagelayout('admin'); +$PAGE->set_title(get_string('enrolmentinstances', 'enrol')); + +$instances = enrol_get_instances($course->id, false); +$plugins = enrol_get_plugins(false); + +if ($canconfig and $action and confirm_sesskey()) { + if (isset($instances[$instanceid]) and isset($plugins[$instances[$instanceid]->enrol])) { + if ($action === 'up') { + $order = array_keys($instances); + $order = array_flip($order); + $pos = $order[$instanceid]; + if ($pos > 0) { + $switch = $pos - 1; + $resorted = array_values($instances); + $temp = $resorted[$pos]; + $resorted[$pos] = $resorted[$switch]; + $resorted[$switch] = $temp; + // now update db sortorder + foreach ($resorted as $sortorder=>$instance) { + if ($instance->sortorder != $sortorder) { + $instance->sortorder = $sortorder; + $DB->update_record('enrol', $instance); + } + } + } + redirect($PAGE->url); + + } else if ($action === 'down') { + $order = array_keys($instances); + $order = array_flip($order); + $pos = $order[$instanceid]; + if ($pos < count($instances) - 1) { + $switch = $pos + 1; + $resorted = array_values($instances); + $temp = $resorted[$pos]; + $resorted[$pos] = $resorted[$switch]; + $resorted[$switch] = $temp; + // now update db sortorder + foreach ($resorted as $sortorder=>$instance) { + if ($instance->sortorder != $sortorder) { + $instance->sortorder = $sortorder; + $DB->update_record('enrol', $instance); + } + } + } + redirect($PAGE->url); + + } else if ($action === 'delete') { + $instance = $instances[$instanceid]; + $plugin = $plugins[$instance->enrol]; + + if ($confirm) { + $plugin->delete_instance($instance); + redirect($PAGE->url); + } + + echo $OUTPUT->header(); + $yesurl = new moodle_url('/enrol/instances.php', array('id'=>$course->id, 'action'=>'delete', 'instance'=>$instance->id, 'confirm'=>1,'sesskey'=>sesskey())); + $displayname = $plugin->get_instance_name($instance); + $users = $DB->count_records('user_enrolments', array('enrolid'=>$instance->id)); + $message = get_string('deleteinstanceconfirm', 'enrol', array('name'=>$displayname, 'users'=>$users)); + echo $OUTPUT->confirm($message, $yesurl, $PAGE->url); + echo $OUTPUT->footer(); + die(); + + } else if ($action === 'disable') { + $instance = $instances[$instanceid]; + if ($instance->status == ENROL_INSTANCE_ENABLED) { + $instance->status = ENROL_INSTANCE_DISABLED; + $DB->update_record('enrol', $instance); + redirect($PAGE->url); + } + + } else if ($action === 'enable') { + $instance = $instances[$instanceid]; + if ($instance->status == ENROL_INSTANCE_DISABLED) { + $instance->status = ENROL_INSTANCE_ENABLED; + $DB->update_record('enrol', $instance); + redirect($PAGE->url); + } + } + } +} + + +echo $OUTPUT->header(); +echo $OUTPUT->heading(get_string('enrolmentinstances', 'enrol')); + +echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthnormal'); + +// display strings +$strup = get_string('up'); +$strdown = get_string('down'); +$strdelete = get_string('delete'); +$strenable = get_string('enable'); +$strdisable = get_string('disable'); +$strmanage = get_string('manageinstance', 'enrol'); + +$table = new html_table(); +$table->head = array(get_string('name'), get_string('users'), $strup.'/'.$strdown, get_string('edit')); +$table->align = array('left', 'center', 'center', 'center'); +$table->width = '100%'; +$table->data = array(); + +// iterate through enrol plugins and add to the display table +$updowncount = 1; +$icount = count($instances); +$url = new moodle_url('/enrol/instances.php', array('sesskey'=>sesskey(), 'id'=>$course->id)); +foreach ($instances as $instance) { + if (!isset($plugins[$instance->enrol])) { + continue; + } + $plugin = $plugins[$instance->enrol]; + + $displayname = $plugin->get_instance_name($instance); + if (!enrol_is_enabled($instance->enrol) or $instance->status != ENROL_INSTANCE_ENABLED) { + $displayname = html_writer::tag('span', $displayname, array('class'=>'dimmed_text')); + } + + $users = $DB->count_records('user_enrolments', array('enrolid'=>$instance->id)); + + $updown = ''; + $edit = ''; + + if ($canconfig) { + // up/down link + $updown = ''; + if ($updowncount > 1) { + $aurl = new moodle_url($url, array('action'=>'up', 'instance'=>$instance->id)); + $updown .= html_writer::link($aurl, html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('t/up'), 'alt'=>$strup, 'class'=>'smallicon'))).' '; + } else { + $updown .= html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('spacer'), 'alt'=>'', 'class'=>'smallicon')).' '; + } + if ($updowncount < $icount) { + $aurl = new moodle_url($url, array('action'=>'down', 'instance'=>$instance->id)); + $updown .= html_writer::link($aurl, html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('t/down'), 'alt'=>$strdown, 'class'=>'smallicon'))).' '; + } else { + $updown .= html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('spacer'), 'alt'=>'', 'class'=>'smallicon')).' '; + } + ++$updowncount; + + // edit links + if ($plugin->instance_deleteable($instance)) { + $aurl = new moodle_url($url, array('action'=>'delete', 'instance'=>$instance->id)); + $edit .= html_writer::link($aurl, html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('t/delete'), 'alt'=>$strdelete, 'class'=>'smallicon'))).' '; + } + + if (enrol_is_enabled($instance->enrol)) { + if ($instance->status == ENROL_INSTANCE_ENABLED) { + $aurl = new moodle_url($url, array('action'=>'disable', 'instance'=>$instance->id)); + $edit .= html_writer::link($aurl, html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('t/hide'), 'alt'=>$strdisable, 'class'=>'smallicon'))).' '; + } else if ($instance->status == ENROL_INSTANCE_DISABLED) { + $aurl = new moodle_url($url, array('action'=>'enable', 'instance'=>$instance->id)); + $edit .= html_writer::link($aurl, html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('t/show'), 'alt'=>$strenable, 'class'=>'smallicon'))).' '; + } else { + // plugin specific state - do not mess with it! + $edit .= html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('t/show'), 'alt'=>'', 'class'=>'smallicon')).' '; + } + + } + } + + // link to instance management + if ($managelink = $plugin->get_manage_link($instance)) { + $displayname = html_writer::link($managelink, $displayname); + } + + // add a row to the table + $table->data[] = array($displayname, $users, $updown, $edit); + +} +echo html_writer::table($table); + +// access security is in each plugin +$candidates = array(); +foreach (enrol_get_plugins(true) as $name=>$plugin) { + if (!$link = $plugin->get_candidate_link($course->id)) { + continue; + } + $candidates[$link->out(false)] = get_string('pluginname', 'enrol_'.$name); +} + +if ($candidates) { + $select = new url_select($candidates); + $select->set_label(get_string('addinstance', 'enrol')); + echo $OUTPUT->render($select); +} + +echo $OUTPUT->box_end(); + +echo $OUTPUT->footer(); diff --git a/enrol/ldap/enrol.php b/enrol/ldap/enrol.php index 9f1827c39c0..a909f449294 100755 --- a/enrol/ldap/enrol.php +++ b/enrol/ldap/enrol.php @@ -1,7 +1,5 @@ dirroot/enrol/enrol.class.php"); - class enrolment_plugin_ldap { var $log; @@ -81,7 +79,8 @@ function setup_enrolments(&$user) { if (!$DB->get_record('role_assignments', array('roleid'=>$role->id, 'userid'=>$user->id, 'contextid'=>$context->id))) { //error_log("[ENROL_LDAP] Assigning role '{$role->name}' to {$user->id} ({$user->username}) in course {$course_obj->id} ({$course_obj->shortname})"); - if (!role_assign($role->id, $user->id, 0, $context->id, 0, 0, 0, 'ldap')){ + //TODO: some real enrolment here + if (!role_assign($role->id, $user->id, $context->id, 'enrol_ldap')){ error_log("[ENROL_LDAP] Failed to assign role '{$role->name}' to $user->id ($user->username) into course $course_obj->id ($course_obj->shortname)"); } } else { @@ -106,7 +105,7 @@ function setup_enrolments(&$user) { foreach ($ldap_assignments as $ra) { if($ra->enrol === 'ldap') { error_log("Unassigning role_assignment with id '{$ra->id}' from user {$user->id} ({$user->username})"); - role_unassign($ra->roleid, $user->id, 0, $ra->contextid, 'ldap'); + role_unassign($ra->roleid, $user->id, $ra->contextid, 'enrol_ldap'); } } @@ -265,11 +264,8 @@ function sync_enrolments($type, $enrol = false) { foreach ($todelete as $member) { $member = $member->user; - if (role_unassign($role->id, $member, 0, $context->id, 'ldap')) { - print "Unassigned $type from $member for course $course_obj->id ($course_obj->shortname)\n"; - } else { - print "Failed to unassign $type from $member for course $course_obj->id ($course_obj->shortname)\n"; - } + role_unassign($role->id, $member, $context->id, 'enrol_ldap'); + print "Unassigned $type from $member for course $course_obj->id ($course_obj->shortname)\n"; } } @@ -287,7 +283,7 @@ function sync_enrolments($type, $enrol = false) { $member = $member->id; if (!$DB->get_record('role_assignments', array('roleid'=>$role->id, 'contextid'=>$context->id, 'userid'=>$member, 'enrol'=>'ldap'))){ - if (role_assign($role->id, $member, 0, $context->id, 0, 0, 0, 'ldap')){ + if (role_assign($role->id, $member, $context->id, 'enrol_ldap')){ print "Assigned role $type to $member ($ldapmember) for course $course_obj->id ($course_obj->shortname)\n"; } else { print "Failed to assign role $type to $member ($ldapmember) for course $course_obj->id ($course_obj->shortname)\n"; diff --git a/enrol/ldap/enrol_ldap_sync.php b/enrol/ldap/enrol_ldap_sync.php index c49995f329b..c94a86d46a1 100755 --- a/enrol/ldap/enrol_ldap_sync.php +++ b/enrol/ldap/enrol_ldap_sync.php @@ -27,9 +27,4 @@ $enrol->sync_enrolments($role->shortname, true); } - // sync metacourses - if (function_exists('sync_metacourses')) { - sync_metacourses(); - } - diff --git a/enrol/manual/addinstance.php b/enrol/manual/addinstance.php new file mode 100644 index 00000000000..0f89a5f84f5 --- /dev/null +++ b/enrol/manual/addinstance.php @@ -0,0 +1,43 @@ +. + +/** + * Adds new instance of enrol_manual to specified course. + * + * @package enrol_manual + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../config.php'); + +$id = required_param('id', PARAM_INT); // course id + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +require_login($course); +require_capability('moodle/course:enrolconfig', $context); +require_sesskey(); + +$enrol = enrol_get_plugin('manual'); + +if ($enrol->get_candidate_link($course->id)) { + $enrol->add_default_instance($course); +} + +redirect(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); diff --git a/enrol/manual/config.html b/enrol/manual/config.html deleted file mode 100644 index 01b3a115b1c..00000000000 --- a/enrol/manual/config.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - -
enrol_manual_keyholderrole: - $role) { - $rolenames[$id]=$role->name; - } - echo html_writer::select($rolenames, 'enrol_manual_keyholderrole', $frm->enrol_manual_keyholderrole); - ?> - - -
enrol_manual_showhint: -enrol_manual_showhint, false); -?> - - -
enrol_manual_usepasswordpolicy: -enrol_manual_usepasswordpolicy, false); -?> - - -
enrol_manual_requirekey: -enrol_manual_requirekey, false); -?> - - -
diff --git a/enrol/manual/db/access.php b/enrol/manual/db/access.php new file mode 100644 index 00000000000..5c0194bf7e1 --- /dev/null +++ b/enrol/manual/db/access.php @@ -0,0 +1,64 @@ +. + +/** + * Capabilities for manual enrolment plugin. + * + * @package enrol_manual + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + +$capabilities = array( + + 'enrol/manual:config' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'manager' => CAP_ALLOW, + ) + ), + + 'enrol/manual:manage' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'manager' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + ) + ), + + + 'enrol/manual:unenrol' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'manager' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + ) + ), + + 'enrol/manual:unenrolself' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + ) + ), + +); + diff --git a/enrol/manual/db/install.php b/enrol/manual/db/install.php new file mode 100644 index 00000000000..eb6c9e2613b --- /dev/null +++ b/enrol/manual/db/install.php @@ -0,0 +1,32 @@ +. + +/** + * Manual enrol plugin installation script + * + * @package enrol_manual + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +function xmldb_enrol_manual_install() { + global $CFG; + + // migrate settings during 2.0 upgrade + +} + diff --git a/enrol/manual/enrol.html b/enrol/manual/enrol.html deleted file mode 100644 index b865562d9b9..00000000000 --- a/enrol/manual/enrol.html +++ /dev/null @@ -1,47 +0,0 @@ -password != '' and !(isguestuser() and !empty($USER->enrolkey[$course->id]))) { // password - echo $OUTPUT->box_start('generalbox centerpara'); - echo '

'; - - $this->print_enrolmentkeyfrom( $course ); - ?> -

- -

errormsg)) {echo $OUTPUT->error_text($this->errormsg);} ?>

- - -
- - - - - -
: - - - - - " /> -
-
-
- -
-
- " /> -
-
- -box_end(); - } - - - if (isguestuser()) { - echo $OUTPUT->box_start('centerpara'); - $loginurl = get_login_url(); - echo $OUTPUT->single_button($loginurl, get_string('login')); - echo $OUTPUT->box_end(); - } -?> diff --git a/enrol/manual/enrol.php b/enrol/manual/enrol.php deleted file mode 100644 index eeff29346ce..00000000000 --- a/enrol/manual/enrol.php +++ /dev/null @@ -1,455 +0,0 @@ -dirroot.'/group/lib.php'); -require_once($CFG->libdir.'/eventslib.php'); - -/** -* enrolment_plugin_manual is the default enrolment plugin -* -* This class provides all the functionality for an enrolment plugin -* In fact it includes all the code for the default, "manual" method -* so that other plugins can override these as necessary. -*/ - -class enrolment_plugin_manual { - -var $errormsg; - -/** -* Prints the entry form/page for this enrolment -* -* This is only called from course/enrol.php -* Most plugins will probably override this to print payment -* forms etc, or even just a notice to say that manual enrolment -* is disabled -* -* @param course current course object -*/ -function print_entry($course) { - global $CFG, $USER, $SESSION, $OUTPUT, $PAGE; - - $strloginto = get_string('loginto', '', $course->shortname); - $strcourses = get_string('courses'); - -/// Automatically enrol into courses without password - - $context = get_context_instance(CONTEXT_SYSTEM); - - $PAGE->navbar->add($strcourses); - $PAGE->navbar->add($strloginto); - - if ($course->password == '') { // no password, so enrol - - if (isguestuser()) { - add_to_log($course->id, 'course', 'guest', 'view.php?id='.$course->id, getremoteaddr()); - - } else if (empty($_GET['confirm']) && empty($_GET['cancel'])) { - $PAGE->set_title($strloginto); - $PAGE->set_heading($course->fullname); - echo $OUTPUT->header(); - echo '
'; - echo $OUTPUT->confirm(get_string('enrolmentconfirmation'), "enrol.php?id=$course->id&confirm=1&sesskey=".sesskey(), "enrol.php?id=$course->id&cancel=1"); - echo $OUTPUT->footer(); - exit; - - } else if (!empty($_GET['confirm']) and confirm_sesskey()) { - - if (!enrol_into_course($course, $USER, 'manual')) { - print_error('couldnotassignrole'); - } - // force a refresh of mycourses - unset($USER->mycourses); - - if (!empty($SESSION->wantsurl)) { - $destination = $SESSION->wantsurl; - unset($SESSION->wantsurl); - } else { - $destination = "$CFG->wwwroot/course/view.php?id=$course->id"; - } - - redirect($destination); - - } else if (!empty($_GET['cancel'])) { - unset($SESSION->wantsurl); - if (!empty($SESSION->enrolcancel)) { - $destination = $SESSION->enrolcancel; - unset($SESSION->enrolcancel); - } else { - $destination = $CFG->wwwroot; - } - redirect($destination); - } - } - - // if we get here we are going to display the form asking for the enrolment key - // and (hopefully) provide information about who to ask for it. - if (!isset($password)) { - $password = ''; - } - - $PAGE->set_title($strloginto); - $PAGE->set_heading($course->fullname); - $PAGE->set_focuscontrol('form.password'); - echo $OUTPUT->header(); - - print_course($course, "80%"); - - include("$CFG->dirroot/enrol/manual/enrol.html"); - - echo $OUTPUT->footer(); - -} - - - -/** -* The other half to print_entry, this checks the form data -* -* This function checks that the user has completed the task on the -* enrolment entry page and then enrolls them. -* -* @param form the form data submitted, as an object -* @param course the current course, as an object -*/ -function check_entry($form, $course) { - global $CFG, $USER, $SESSION; - - if (empty($form->password)) { - $form->password = ''; - } - - if (empty($course->password) or !confirm_sesskey()) { - // do not allow entry when no course password set - // automatic login when manual primary, no login when secondary at all!! - print_error('invalidenrol'); - } - - $groupid = $this->check_group_entry($course->id, $form->password); - - if (($form->password == $course->password) or ($groupid !== false) ) { - - if (isguestuser()) { // only real user guest, do not use this for users with guest role - $USER->enrolkey[$course->id] = true; - add_to_log($course->id, 'course', 'guest', 'view.php?id='.$course->id, getremoteaddr()); - - } else { /// Update or add new enrolment - if (enrol_into_course($course, $USER, 'manual')) { - // force a refresh of mycourses - unset($USER->mycourses); - if ($groupid !== false) { - if (!groups_add_member($groupid, $USER->id)) { - print_error('couldnotassigngroup'); - } - } - } else { - print_error('couldnotassignrole'); - } - } - - if ($SESSION->wantsurl) { - $destination = $SESSION->wantsurl; - unset($SESSION->wantsurl); - } else { - $destination = "$CFG->wwwroot/course/view.php?id=$course->id"; - } - - redirect($destination); - - } else if (!isset($CFG->enrol_manual_showhint) or $CFG->enrol_manual_showhint) { - $this->errormsg = get_string('enrolmentkeyhint', '', substr($course->password, 0, 1)); - - } else { - $this->errormsg = get_string('enrolmentkeyerror', 'enrol_manual'); - } -} - - -/** -* Check if the given enrolment key matches a group enrolment key for the given course -* -* @param courseid the current course id -* @param password the submitted enrolment key -*/ -function check_group_entry ($courseid, $password) { - - if ($groups = groups_get_all_groups($courseid)) { - foreach ($groups as $group) { - if ( !empty($group->enrolmentkey) and ($password == $group->enrolmentkey) ) { - return $group->id; - } - } - } - - return false; -} - - -/** -* Prints a form for configuring the current enrolment plugin -* -* This function is called from admin/enrol.php, and outputs a -* full page with a form for defining the current enrolment plugin. -* -* @param frm an object containing all the data for this page -*/ -function config_form($frm) { - global $CFG, $OUTPUT; - - if (!isset( $frm->enrol_manual_keyholderrole )) { - $frm->enrol_manual_keyholderrole = ''; - } - - if (!isset($frm->enrol_manual_showhint)) { - $frm->enrol_manual_showhint = 1; - } - - if (!isset($frm->enrol_manual_usepasswordpolicy)) { - $frm->enrol_manual_usepasswordpolicy = 0; - } - - if (!isset($frm->enrol_manual_requirekey)) { - $frm->enrol_manual_requirekey = 0; - } - - include ("$CFG->dirroot/enrol/manual/config.html"); -} - - -/** -* Processes and stored configuration data for the enrolment plugin -* -* @param config all the configuration data as entered by the admin -*/ -function process_config($config) { - foreach ($config as $name => $value) { - set_config($name, $value); - } - - return true; -} - - -/** -* Notify users about enrolments that are going to expire soon! -* This function is run by admin/cron.php -* @return void -*/ -function cron() { - global $CFG, $USER, $SITE, $DB; - - if (!isset($CFG->lastexpirynotify)) { - set_config('lastexpirynotify', 0); - } - - // notify once a day only - TODO: add some tz handling here, maybe use timestamps - if ($CFG->lastexpirynotify == date('Ymd')) { - return; - } - - if ($rs = $DB->get_recordset_select('course', 'enrolperiod > 0 AND expirynotify > 0 AND expirythreshold > 0')) { - $admin = get_admin(); - - foreach ($rs as $course) { - $a = new object(); - $a->coursename = $course->shortname .'/'. $course->fullname; // must be processed by format_string later - $a->threshold = $course->expirythreshold / 86400; - $a->extendurl = $CFG->wwwroot . '/user/index.php?id=' . $course->id; - $a->current = array(); - $a->past = array(); - - $expiry = time() + $course->expirythreshold; - $cname = $course->fullname; - - /// Get all the manual role assignments for this course that have expired. - - if (!$context = get_context_instance(CONTEXT_COURSE, $course->id)) { - continue; - } - - if ($oldenrolments = $DB->get_records_sql(" - SELECT u.*, ra.timeend - FROM {user} u - JOIN {role_assignments} ra ON (ra.userid = u.id) - WHERE ra.contextid = $context->id - AND ra.timeend > 0 AND ra.timeend <= $expiry - AND ra.enrol = 'manual'")) { - - // inform user who can assign roles or admin - if ($teachers = get_users_by_capability($context, 'moodle/role:assign', '', '', '', '', '', '', false)) { - $teachers = sort_by_roleassignment_authority($teachers, $context); - $teacher = reset($teachers); - } else { - $teachers = array($admin); - $teacher = $admin; - } - - $a->teacherstr = fullname($teacher, true); - - foreach ($oldenrolments as $user) { /// Email all users about to expire - $a->studentstr = fullname($user, true); - if ($user->timeend < ($expiry - 86400)) { - $a->past[] = fullname($user) . " <$user->email>"; - } else { - $a->current[] = fullname($user) . " <$user->email>"; - if ($course->notifystudents) { // Send this guy notice - // setup global $COURSE properly - needed for languages - cron_setup_user($user, $course); - $a->coursename = format_string($cname); - $a->course = $a->coursename; - $strexpirynotifystudentsemail = get_string('expirynotifystudentsemail', '', $a); - $strexpirynotify = get_string('expirynotify'); - - $eventdata = new object(); - $eventdata->modulename = 'moodle'; - $eventdata->userfrom = $teacher; - $eventdata->userto = $user; - $eventdata->subject = format_string($SITE->fullname) .' '. $strexpirynotify; - $eventdata->fullmessage = $strexpirynotifystudentsemail; - $eventdata->fullmessageformat = FORMAT_PLAIN; - $eventdata->fullmessagehtml = ''; - $eventdata->smallmessage = ''; - message_send($eventdata); - } - } - } - - $a->current = implode("\n", $a->current); - $a->past = implode("\n", $a->past); - - if ($a->current || $a->past) { - foreach ($teachers as $teacher) { - // setup global $COURSE properly - needed for languages - cron_setup_user($teacher, $course); - $a->coursename = format_string($cname); - $strexpirynotifyemail = get_string('expirynotifyemail', '', $a); - $strexpirynotify = get_string('expirynotify'); - - $eventdata = new object(); - $eventdata->modulename = 'moodle'; - $eventdata->userfrom = $admin; - $eventdata->userto = $teacher; - $eventdata->subject = $a->coursename .' '. $strexpirynotify; - $eventdata->fullmessage = $strexpirynotifyemail; - $eventdata->fullmessageformat = FORMAT_PLAIN; - $eventdata->fullmessagehtml = ''; - $eventdata->smallmessage = ''; - message_send($eventdata); - } - } - } - } - $rs->close(); - cron_setup_user(); - } - - set_config('lastexpirynotify', date('Ymd')); -} - - -/** -* Returns the relevant icons for a course -* -* @param course the current course, as an object -*/ -function get_access_icons($course) { - global $CFG, $OUTPUT; - - global $strallowguests; - global $strrequireskey; - - if (empty($strallowguests)) { - $strallowguests = get_string('allowguests'); - $strrequireskey = get_string('requireskey'); - } - - $str = ''; - - if (!empty($course->guest)) { - $str .= ''; - $str .= ''.$strallowguests.'  '; - } - if (!empty($course->password)) { - $str .= ''; - $str .= ''.$strrequireskey.''; - } - - return $str; -} - -/** - * Prints the message telling you were to get the enrolment key - * appropriate for the prevailing circumstances - * A bit clunky because I didn't want to change the standard strings - */ -function print_enrolmentkeyfrom($course) { - global $CFG, $USER; - - $context = get_context_instance(CONTEXT_SYSTEM); - - // if a keyholder role is defined we list teachers in that role (if any exist) - $contactslisted = false; - if (!empty($CFG->enrol_manual_keyholderrole)) { - if ($contacts = get_role_users($CFG->enrol_manual_keyholderrole, get_context_instance(CONTEXT_COURSE, $course->id),true,'','u.lastname ASC')) { - // guest user has a slightly different message - if (isguestuser()) { - print_string('enrolmentkeyfromguest', '', ':
' ); - } - else { - print_string('enrolmentkeyfrom', '', ':
'); - } - foreach ($contacts as $contact) { - $contactname = "id&course=".SITEID."\">".fullname($contact)."."; - echo "$contactname
"; - } - $contactslisted = true; - } - } - - // if no keyholder role is defined OR nobody is in that role we do this the 'old' way - // (show the first person with update rights) - if (!$contactslisted) { - if ($teachers = get_users_by_capability(get_context_instance(CONTEXT_COURSE, $course->id), 'moodle/course:update', - 'u.*', 'u.id ASC', 0, 1, '', '', false, true)) { - $teacher = array_shift($teachers); - } - if (!empty($teacher)) { - $teachername = "id&course=".SITEID."\">".fullname($teacher)."."; - } else { - $teachername = strtolower( get_string('defaultcourseteacher') ); - } - - // guest user has a slightly different message - if (isguestuser()) { - print_string('enrolmentkeyfromguest', '', $teachername ); - } - else { - print_string('enrolmentkeyfrom', '', $teachername); - } - } -} - -} /// end of class - - diff --git a/enrol/manual/lang/en/enrol_manual.php b/enrol/manual/lang/en/enrol_manual.php index 439561b1389..52fd1d118ef 100644 --- a/enrol/manual/lang/en/enrol_manual.php +++ b/enrol/manual/lang/en/enrol_manual.php @@ -23,16 +23,19 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -$string['description'] = 'This is the default form of enrolment. There are two main ways a student can be enrolled in a particular course. -
    -
  • A teacher or admin can enrol them manually using the link in the Course Administration menu - within the course.
  • -
  • A course can have a password defined, known as an "enrolment key". Anyone who knows this key is - able to add themselves to a course.
  • -
'; -$string['enrol_manual_requirekey'] = 'Require course enrolment keys in new courses and prevent removing of existing keys.'; -$string['enrol_manual_showhint'] = 'Enable this setting to reveal the first character of the enrolment key as a hint if one enters an incorrect key.'; -$string['enrol_manual_usepasswordpolicy'] = 'Use current user password policy for course enrolment keys.'; -$string['enrolmentkeyerror'] = 'That enrolment key was incorrect, please try again.'; -$string['enrolname'] = 'Internal Enrolment'; -$string['keyholderrole'] = 'The role of the user that holds the enrolment key for a course. Displayed to students attempting to enrol on the course.'; +$string['assignrole'] = 'Assignrole'; +$string['defaultperiod'] = 'Default enrolment period'; +$string['defaultperiod_desc'] = 'Default length of the default enrolment period setting (in seconds).'; //TODO: fixme +$string['enrolledincourserole'] = 'Enrolled in "{$a->course}" as "{$a->role}"'; +$string['enrolusers'] = 'Enrol users'; +$string['manual:config'] = 'Configure manual enrol instances'; +$string['manual:manage'] = 'Manage enrolled users'; +$string['manual:unenrol'] = 'Unenrol users from the course'; +$string['manual:unenrolself'] = 'Unenrol self from the course'; +$string['pluginname'] = 'Manual enrolments'; +$string['pluginname_desc'] = 'Internal enrolments is a basic enrolment plugin which allows simple user enrolments. It should be kept enabled in most cases. Some other plugins such as self enrolment may use this pugin internally.'; +$string['status'] = 'Enable manual enrolments'; +$string['status_desc'] = 'Allow course access of internally enrolled users. This should be kept enabled in most cases.'; +$string['statusenabled'] = 'Enabled'; +$string['statusdisabled'] = 'Disabled'; +$string['unenrolselfconfirm'] = 'Do you really want to unenrol yourself from course "{$a}"?'; \ No newline at end of file diff --git a/enrol/manual/lib.php b/enrol/manual/lib.php new file mode 100644 index 00000000000..57c7d57229e --- /dev/null +++ b/enrol/manual/lib.php @@ -0,0 +1,222 @@ +. + +/** + * Manual enrolment plugin main library file. + * + * @package enrol_manual + * @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; + +class enrol_manual_plugin extends enrol_plugin { + + 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; + } + + /** + * Returns link to manual enrol UI if exists. + * Does the access control tests automatically. + * + * @param object $instance + * @return moodle_url + */ + public function get_manual_enrol_link($instance) { + $name = $this->get_name(); + if ($instance->enrol !== $name) { + throw new coding_exception('invalid enrol instance!'); + } + + if ($instance->courseid == SITEID) { + return NULL; + } + + if (!enrol_is_enabled($name)) { + return NULL; + } + + $context = get_context_instance(CONTEXT_COURSE, $instance->courseid, MUST_EXIST); + + if (!has_capability('enrol/manual:manage', $context)) { + return NULL; + } + + return new moodle_url('/enrol/manual/manage.php', array('enrolid'=>$instance->id, 'id'=>$instance->courseid)); + } + + /** + * 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_candidate_link($courseid) { + global $DB; + + if (!has_capability('moodle/course:enrolconfig', get_context_instance(CONTEXT_COURSE, $courseid, MUST_EXIST))) { + return NULL; + } + + if ($DB->record_exists('enrol', array('courseid'=>$courseid, 'enrol'=>'manual'))) { + return NULL; + } + + return new moodle_url('/enrol/manual/addinstance.php', array('sesskey'=>sesskey(), 'id'=>$courseid)); + } + + /** + * Adds enrol instance UI to course edit form + * + * @param object $instance enrol instance or null if does not exist yet + * @param MoodleQuickForm $mform + * @param object $data + * @param object $context context of existing course or parent category if course does not exist + * @return void + */ + public function course_edit_form($instance, MoodleQuickForm $mform, $data, $context) { + + $i = isset($instance->id) ? $instance->id : 0; + $plugin = enrol_get_plugin('manual'); + $header = $plugin->get_instance_name($instance); + $config = has_capability('enrol/manual:config', $context); + + $mform->addElement('header', 'enrol_manual_header_'.$i, $header); + + + $options = array(ENROL_INSTANCE_ENABLED => get_string('yes'), + ENROL_INSTANCE_DISABLED => get_string('no')); + $mform->addElement('select', 'enrol_manual_status_'.$i, get_string('status', 'enrol_manual'), $options); + $mform->setDefault('enrol_manual_status_'.$i, $this->get_config('status')); + $mform->setAdvanced('enrol_manual_status_'.$i, $this->get_config('status_adv')); + if (!$config) { + $mform->hardFreeze('enrol_manual_status_'.$i); + } + + + $mform->addElement('duration', 'enrol_manual_enrolperiod_'.$i, get_string('defaultperiod', 'enrol_manual'), array('optional' => true, 'defaultunit' => 86400)); + $mform->setDefault('enrol_manual_enrolperiod_'.$i, $this->get_config('enrolperiod')); + $mform->setAdvanced('enrol_manual_enrolperiod_'.$i, $this->get_config('enrolperiod_adv')); + if (!$config) { + $mform->hardFreeze('enrol_manual_enrolperiod_'.$i); + } else { + $mform->disabledIf('enrol_manual_enrolperiod_'.$i, 'enrol_manual_status_'.$i, 'noteq', ENROL_INSTANCE_ENABLED); + } + + + if ($instance) { + $roles = get_default_enrol_roles($context, $instance->roleid); + } else { + $roles = get_default_enrol_roles($context, $this->get_config('roleid')); + } + $mform->addElement('select', 'enrol_manual_roleid_'.$i, get_string('defaultrole', 'role'), $roles); + $mform->setDefault('enrol_manual_roleid_'.$i, $this->get_config('roleid')); + $mform->setAdvanced('enrol_manual_roleid_'.$i, $this->get_config('roleid_adv')); + if (!$config) { + $mform->hardFreeze('enrol_manual_roleid_'.$i); + } else { + $mform->disabledIf('enrol_manual_roleid_'.$i, 'enrol_manual_status_'.$i, 'noteq', ENROL_INSTANCE_ENABLED); + } + + + // now add all values from enrol table + if ($instance) { + foreach($instance as $key=>$val) { + $data->{'enrol_manual_'.$key.'_'.$i} = $val; + } + } + } + + /** + * Called after updating/inserting course. + * + * @param bool $inserted true if course just inserted + * @param object $course + * @param object $data form data + * @return void + */ + public function course_updated($inserted, $course, $data) { + global $DB; + + $context = get_context_instance(CONTEXT_COURSE, $course->id); + if (has_capability('enrol/manual:config', $context)) { + if ($inserted) { + if (isset($data->enrol_manual_status_0)) { + $fields = array('status'=>$data->enrol_manual_status_0); + if ($fields['status'] == ENROL_INSTANCE_ENABLED) { + $fields['enrolperiod'] = $data->enrol_manual_enrolperiod_0; + $fields['roleid'] = $data->enrol_manual_roleid_0; + } else { + $fields['enrolperiod'] = $this->get_config('enrolperiod'); + $fields['roleid'] = $this->get_config('roleid'); + } + $this->add_instance($course, $fields); + } + } else { + $instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'manual')); + foreach ($instances as $instance) { + $i = $instance->id; + if (isset($data->{'enrol_manual_status_'.$i})) { + $instance->status = $data->{'enrol_manual_status_'.$i}; + $instance->timemodified = time(); + if ($instance->status == ENROL_INSTANCE_ENABLED) { + $instance->enrolperiod = $data->{'enrol_manual_enrolperiod_'.$i}; + $instance->roleid = $data->{'enrol_manual_roleid_'.$i}; + } + $DB->update_record('enrol', $instance); + } + } + } + + } else { + if ($inserted) { + if ($this->get_config('defaultenrol')) { + $this->add_default_instance($course); + } + } else { + // bad luck, user can not change anything + } + } + } + + /** + * Add new instance of enrol plugin with default settings. + * @param object $course + * @return int id of new instance + */ + public function add_default_instance($course) { + $fields = array('status'=>$this->get_config('status'), 'enrolperiod'=>$this->get_config('enrolperiod', 0), 'roleid'=>$this->get_config('roleid', 0)); + return $this->add_instance($course, $fields); + } + + public function cron() { + // TODO: deal with $CFG->longtimenosee + } +} + diff --git a/enrol/manual/locallib.php b/enrol/manual/locallib.php new file mode 100644 index 00000000000..bdf74a4ac68 --- /dev/null +++ b/enrol/manual/locallib.php @@ -0,0 +1,154 @@ +. + +/** + * Auxiliary manual user enrolment lib, the main purpose is to lower memory requirements... + * + * @package enrol_manual + * @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->dirroot . '/user/selector/lib.php'); + +/** + * Enrol candidates + */ +class enrol_manual_potential_participant extends user_selector_base { + protected $enrolid; + + public function __construct($name, $options) { + $this->enrolid = $options['enrolid']; + parent::__construct($name, $options); + } + + /** + * Candidate users + * @param $search + * @return array + */ + public function find_users($search) { + global $DB; + //by default wherecondition retrieves all users except the deleted, not confirmed and guest + list($wherecondition, $params) = $this->search_sql($search, 'u'); + $params['enrolid'] = $this->enrolid; + + $fields = 'SELECT ' . $this->required_fields_sql('u'); + $countfields = 'SELECT COUNT(1)'; + + $sql = " FROM {user} u + WHERE $wherecondition + AND u.id NOT IN (SELECT ue.userid + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.id = :enrolid))"; + + $order = ' ORDER BY u.lastname ASC, u.firstname ASC'; + + if (!$this->is_validating()) { + $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); + if ($potentialmemberscount > 100) { + return $this->too_many_results($search, $potentialmemberscount); + } + } + + $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + + if (empty($availableusers)) { + return array(); + } + + + if ($search) { + $groupname = get_string('enrolcandidatesmatching', 'enrol', $search); + } else { + $groupname = get_string('enrolcandidates', 'enrol'); + } + + return array($groupname => $availableusers); + } + + protected function get_options() { + $options = parent::get_options(); + $options['enrolid'] = $this->enrolid; + $options['file'] = 'enrol/manual/locallib.php'; + return $options; + } +} + +/** + * Enroled users + */ +class enrol_manual_current_participant extends user_selector_base { + protected $courseid; + protected $enrolid; + + public function __construct($name, $options) { + $this->enrolid = $options['enrolid']; + parent::__construct($name, $options); + } + + /** + * Candidate users + * @param $search + * @return array + */ + public function find_users($search) { + global $DB; + //by default wherecondition retrieves all users except the deleted, not confirmed and guest + list($wherecondition, $params) = $this->search_sql($search, 'u'); + $params['enrolid'] = $this->enrolid; + + $fields = 'SELECT ' . $this->required_fields_sql('u'); + $countfields = 'SELECT COUNT(1)'; + + $sql = " FROM {user} u + JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid) + WHERE $wherecondition"; + + $order = ' ORDER BY u.lastname ASC, u.firstname ASC'; + + if (!$this->is_validating()) { + $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); + if ($potentialmemberscount > 100) { + return $this->too_many_results($search, $potentialmemberscount); + } + } + + $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + + if (empty($availableusers)) { + return array(); + } + + + if ($search) { + $groupname = get_string('enrolledusersmatching', 'enrol', $search); + } else { + $groupname = get_string('enrolledusers', 'enrol'); + } + + return array($groupname => $availableusers); + } + + protected function get_options() { + $options = parent::get_options(); + $options['enrolid'] = $this->enrolid; + $options['file'] = 'enrol/manual/locallib.php'; + return $options; + } +} diff --git a/enrol/manual/manage.php b/enrol/manual/manage.php new file mode 100644 index 00000000000..3a37aa866d6 --- /dev/null +++ b/enrol/manual/manage.php @@ -0,0 +1,188 @@ +. + +/** + * Manual user enrolment UI. + * + * @package enrol_manual + * @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($CFG->dirroot.'/enrol/manual/locallib.php'); + +$enrolid = required_param('enrolid', PARAM_INT); +$roleid = optional_param('roleid', -1, PARAM_INT); +$extendperiod = optional_param('extendperiod', 0, PARAM_INT); +$extendbase = optional_param('extendbase', 3, PARAM_INT); + +$instance = $DB->get_record('enrol', array('id'=>$enrolid, 'enrol'=>'manual'), '*', MUST_EXIST); +$course = $DB->get_record('course', array('id'=>$instance->courseid), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +require_login($course); +require_capability('enrol/manual:manage', $context); + +$instance = $DB->get_record('enrol', array('id'=>$enrolid, 'enrol'=>'manual'), '*', MUST_EXIST); +if ($roleid < 0) { + $roleid = $instance->roleid; +} +$roles = get_assignable_roles($context); +$roles = array('0'=>get_string('none')) + $roles; + +if (!isset($roles[$roleid])) { + // weird - security always first! + $roleid = 0; +} + +if (!$enrol_manual = enrol_get_plugin('manual')) { + throw coding_error('Can not instantiate enrol_manual'); +} + +$instancename = $enrol_manual->get_instance_name($instance); + +$PAGE->set_url('/enrol/manual/manage.php', array('enrolid'=>$instance->id)); +$PAGE->set_pagelayout('admin'); +$PAGE->set_title($enrol_manual->get_instance_name($instance)); + +// Create the user selector objects. +$options = array('enrolid' => $enrolid); + +$potentialuserselector = new enrol_manual_potential_participant('addselect', $options); +$currentuserselector = new enrol_manual_current_participant('removeselect', $options); + +// Build the list of options for the enrolment period dropdown. +$unlimitedperiod = get_string('unlimited'); +$periodmenu = array(); +for ($i=1; $i<=365; $i++) { + $seconds = $i * 86400; + $periodmenu[$seconds] = get_string('numdays', '', $i); +} +// Work out the apropriate default setting. +if ($extendperiod) { + $defaultperiod = $extendperiod; +} else { + $defaultperiod = $instance->enrolperiod; +} + +// Build the list of options for the starting from dropdown. +$timeformat = get_string('strftimedatefullshort'); +$today = time(); +$today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0); + +// enrolment start +$basemenu = array(); +if ($course->startdate > 0) { + $basemenu[2] = get_string('coursestart') . ' (' . userdate($course->startdate, $timeformat) . ')'; +} +$basemenu[3] = get_string('today') . ' (' . userdate($today, $timeformat) . ')' ; + +// process add and removes +if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) { + $userstoassign = $potentialuserselector->get_selected_users(); + if (!empty($userstoassign)) { + foreach($userstoassign as $adduser) { + switch($extendbase) { + case 2: + $timestart = $course->startdate; + break; + case 3: + default: + $timestart = $today; + break; + } + + if ($extendperiod <= 0) { + $timestart = 0; + $timeend = 0; + } else { + $timeend = $timestart + $extendperiod; + } + $enrol_manual->enrol_user($instance, $adduser->id, $roleid, $timestart, $timeend, true); + add_to_log($course->id, 'course', 'enrol', '../enrol/users.php?id='.$course->id, $course->id); //there should be userid somewhere! + } + + $potentialuserselector->invalidate_selected_users(); + $currentuserselector->invalidate_selected_users(); + + //TODO: log + } +} + +// Process incoming role unassignments +if (optional_param('remove', false, PARAM_BOOL) && confirm_sesskey()) { + $userstounassign = $currentuserselector->get_selected_users(); + if (!empty($userstounassign)) { + foreach($userstounassign as $removeuser) { + $enrol_manual->unenrol_user($instance, $removeuser->id); + add_to_log($course->id, 'course', 'unenrol', '../enrol/users.php?id='.$course->id, $course->id); //there should be userid somewhere! + } + + $potentialuserselector->invalidate_selected_users(); + $currentuserselector->invalidate_selected_users(); + + //TODO: log + } +} + + +echo $OUTPUT->header(); +echo $OUTPUT->heading($instancename); + +?> +
+ + + + + + + + +
+

+ display() ?> +
+
+
+ +
+ +


+

+ +


+

+ +


+

+ +
+
+ +
+ +
+
+

+ display() ?> +
+
+footer(); diff --git a/enrol/manual/settings.php b/enrol/manual/settings.php new file mode 100644 index 00000000000..851ccbfc062 --- /dev/null +++ b/enrol/manual/settings.php @@ -0,0 +1,60 @@ +. + +/** + * Manual enrolment plugin settings and presets. + * + * @package enrol_manual + * @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_manual_settings', '', get_string('pluginname_desc', 'enrol_manual'))); + + + //--- enrol instance defaults ---------------------------------------------------------------------------- + $settings->add(new admin_setting_heading('enrol_manual_defaults', + get_string('enrolinstancedefaults', 'admin'), get_string('enrolinstancedefaults_desc', 'admin'))); + + $settings->add(new admin_setting_configcheckbox('enrol_manual/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_with_advanced('enrol_manual/status', + get_string('status', 'enrol_manual'), get_string('status_desc', 'enrol_manual'), + array('value'=>ENROL_INSTANCE_ENABLED, 'adv'=>false), $options)); + + $settings->add(new admin_setting_configtext_with_advanced('enrol_manual/enrolperiod', + get_string('defaultperiod', 'enrol_manual'), get_string('defaultperiod_desc', 'enrol_manual'), + array('value'=>0, 'adv'=>true), PARAM_INT)); + + if (!during_initial_install()) { + $options = get_default_enrol_roles(get_context_instance(CONTEXT_SYSTEM)); + $student = get_archetype_roles('student'); + $student = reset($student); + $settings->add(new admin_setting_configselect_with_advanced('enrol_manual/roleid', + get_string('defaultrole', 'role'), '', + array('value'=>$student->id, 'adv'=>true), $options)); + } +} + diff --git a/enrol/manual/unenrolself.php b/enrol/manual/unenrolself.php new file mode 100644 index 00000000000..fdb2a45ae9f --- /dev/null +++ b/enrol/manual/unenrolself.php @@ -0,0 +1,58 @@ +. + +/** + * Manual enrolment plugin - support for user self unenrolment. + * + * @package enrol_manual + * @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'=>'manual'), '*', MUST_EXIST); +$course = $DB->get_record('course', array('id'=>$instance->courseid), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +require_login($course); + +$plugin = enrol_get_plugin('manual'); + +// security defined inside following function +if (!$plugin->get_unenrolself_link($instance)) { + redirect(new moodle_url('/course/view.php', array('id'=>$course->id))); +} + +$PAGE->set_url('/enrol/manual/unenrolself.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); //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('unenrolselfconfirm', 'enrol_manual', format_string($course->fullname)); +echo $OUTPUT->confirm($message, $yesurl, $nourl); +echo $OUTPUT->footer(); diff --git a/enrol/manual/version.php b/enrol/manual/version.php new file mode 100644 index 00000000000..fd209b7a96a --- /dev/null +++ b/enrol/manual/version.php @@ -0,0 +1,26 @@ +. + +/** + * Manual enrolment plugin version specification. + * + * @package enrol_manual + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$plugin->version = 2010061500; diff --git a/enrol/meta/addinstance.php b/enrol/meta/addinstance.php new file mode 100644 index 00000000000..6fa2f1e099a --- /dev/null +++ b/enrol/meta/addinstance.php @@ -0,0 +1,60 @@ +. + +/** + * Adds new instance of enrol_meta to specified course. + * + * @package enrol_meta + * @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("$CFG->dirroot/enrol/meta/addinstance_form.php"); +require_once("$CFG->dirroot/enrol/meta/locallib.php"); + +$id = required_param('id', PARAM_INT); // course id + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +require_login($course); +require_capability('moodle/course:enrolconfig', $context); + +$enrol = enrol_get_plugin('meta'); +if (!$enrol->get_candidate_link($course->id)) { + redirect(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); +} + +$mform = new enrol_meta_addinstance_form(NULL, $course); + +if ($mform->is_cancelled()) { + redirect(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); + +} else if ($data = $mform->get_data()) { + $eid = $enrol->add_instance($course, array('customint1'=>$data->link)); + enrol_meta_sync($course->id); + redirect(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); +} + +$PAGE->set_url('/enrol/meta/addinstance.php', array('id'=>$course->id)); + +echo $OUTPUT->header(); + +$mform->display(); + +echo $OUTPUT->footer(); diff --git a/enrol/meta/addinstance_form.php b/enrol/meta/addinstance_form.php new file mode 100644 index 00000000000..980aaf71cc8 --- /dev/null +++ b/enrol/meta/addinstance_form.php @@ -0,0 +1,96 @@ +. + +/** + * Adds instance form + * + * @package enrol_meta + * @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_meta_addinstance_form extends moodleform { + protected $course; + + function definition() { + global $CFG, $DB; + + $mform = $this->_form; + $course = $this->_customdata; + $this->course = $course; + + $existing = $DB->get_records('enrol', array('enrol'=>'meta', 'courseid'=>$course->id), '', 'customint1, id'); + + // TODO: this has to be done via ajax or else it will fail very badly on large sites! + $courses = array('' => get_string('choosedots')); + $rs = $DB->get_recordset('course', array(), 'sortorder ASC', 'id, fullname, shortname, visible'); + foreach ($rs as $c) { + if ($c->id == SITEID or $c->id == $course->id or isset($existing[$c->id])) { + continue; + } + $coursecontext = get_context_instance(CONTEXT_COURSE, $c->id); + if (!$c->visible and !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { + continue; + } + if (!has_capability('enrol/meta:selectaslinked', $coursecontext)) { + continue; + } + $courses[$c->id] = format_string($c->fullname). ' ['.$c->shortname.']'; + } + $rs->close(); + + $mform->addElement('header','general', get_string('pluginname', 'enrol_meta')); + + $mform->addElement('select', 'link', get_string('linkedcourse', 'enrol_meta'), $courses); + $mform->addRule('link', get_string('required'), 'required', null, 'client'); + + $mform->addElement('hidden', 'id', null); + $mform->setType('id', PARAM_INT); + + $this->add_action_buttons(); + + $this->set_data(array('id'=>$course->id)); + } + + function validation($data, $files) { + global $DB, $CFG; + + // TODO: this is duplicated here because it may be necessary one we implement ajax course selection element + + $errors = parent::validation($data, $files); + if (!$c = $DB->get_record('course', array('id'=>$data['link']))) { + $errors['link'] = get_string('required'); + } else { + $coursecontext = get_context_instance(CONTEXT_COURSE, $c->id); + $existing = $DB->get_records('enrol', array('enrol'=>'meta', 'courseid'=>$this->course->id), '', 'customint1, id'); + if (!$c->visible and !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { + $errors['link'] = get_string('error'); + } else if (!has_capability('enrol/meta:selectaslinked', $coursecontext)) { + $errors['link'] = get_string('error'); + } else if ($c->id == SITEID or $c->id == $this->course->id or isset($existing[$c->id])) { + $errors['link'] = get_string('error'); + } + } + + return $errors; + } +} + diff --git a/enrol/meta/db/access.php b/enrol/meta/db/access.php new file mode 100644 index 00000000000..1bbb946ed57 --- /dev/null +++ b/enrol/meta/db/access.php @@ -0,0 +1,45 @@ +. + +/** + * Capabilities for meta link access plugin. + * + * @package enrol_meta + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$capabilities = array( + 'enrol/meta:config' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'manager' => CAP_ALLOW, + ) + ), + + // select some course as source + 'enrol/meta:selectaslinked' => array( + 'captype' => 'read', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'manager' => CAP_ALLOW, + ) + ), +); + + diff --git a/enrol/meta/db/events.php b/enrol/meta/db/events.php new file mode 100644 index 00000000000..541d9b66e2f --- /dev/null +++ b/enrol/meta/db/events.php @@ -0,0 +1,57 @@ +. + +/** + * Meta course enrolment plugin event handler definition. + * + * @package enrol_meta + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/* List of handlers */ +$handlers = array ( + 'role_assigned' => array ( + 'handlerfile' => '/enrol/meta/locallib.php', + 'handlerfunction' => array('enrol_meta_handler', 'role_assigned'), + 'schedule' => 'instant' + ), + + 'role_unassigned' => array ( + 'handlerfile' => '/enrol/meta/locallib.php', + 'handlerfunction' => array('enrol_meta_handler', 'role_unassigned'), + 'schedule' => 'instant' + ), + + 'user_enrolled' => array ( + 'handlerfile' => '/enrol/meta/locallib.php', + 'handlerfunction' => array('enrol_meta_handler', 'user_enrolled'), + 'schedule' => 'instant' + ), + + 'user_unenrolled' => array ( + 'handlerfile' => '/enrol/meta/locallib.php', + 'handlerfunction' => array('enrol_meta_handler', 'user_unenrolled'), + 'schedule' => 'instant' + ), + + 'course_deleted' => array ( + 'handlerfile' => '/enrol/meta/locallib.php', + 'handlerfunction' => array('enrol_meta_handler', 'course_deleted'), + 'schedule' => 'instant' + ), +); diff --git a/enrol/meta/db/install.php b/enrol/meta/db/install.php new file mode 100644 index 00000000000..e490cc40443 --- /dev/null +++ b/enrol/meta/db/install.php @@ -0,0 +1,42 @@ +. + +/** + * Meta link enrolment plugin installation. + * + * @package enrol_manual + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +function xmldb_enrol_meta_install() { + global $CFG, $DB; + + if (isset($CFG->nonmetacoursesyncroleids)) { + set_config('nosyncroleids', $CFG->nonmetacoursesyncroleids, 'enrol_meta'); + unset_config('nonmetacoursesyncroleids'); + } + + if (!$DB->record_exists('enrol', array('enrol'=>'meta'))) { + // no need to syn roles and enrolments + return; + } + + // brute force course resync, this may take a while + require_once("$CFG->dirroot/enrol/meta/locallib.php"); + enrol_meta_sync(); +} diff --git a/enrol/meta/lang/en/enrol_meta.php b/enrol/meta/lang/en/enrol_meta.php new file mode 100644 index 00000000000..eed0c456742 --- /dev/null +++ b/enrol/meta/lang/en/enrol_meta.php @@ -0,0 +1,32 @@ +. + +/** + * Strings for component 'enrol_meta', language 'en', branch 'MOODLE_20_STABLE' + * + * @package enrol_meta + * @copyright 2010 onwards Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['linkedcourse'] = 'Link course'; +$string['meta:config'] = 'Configure meta link enrol instances'; +$string['meta:selectaslinked'] = 'Select course as meta linked'; +$string['nosyncroleids'] = 'Roles that are not synchronised'; +$string['nosyncroleids_desc'] = 'By default all course level role assignments are synchronised from parent to child courses. Roles that are selected here will not be included in the synchronisation process. The current roles will be updated in the next cron execution.'; +$string['pluginname'] = 'Course meta link'; +$string['pluginname_desc'] = 'Course meta link enrolment plugin synchronises enrolments and roles in two different courses.'; diff --git a/enrol/meta/lib.php b/enrol/meta/lib.php new file mode 100644 index 00000000000..7323ead6a31 --- /dev/null +++ b/enrol/meta/lib.php @@ -0,0 +1,107 @@ +. + +/** + * Meta course enrolment plugin. + * + * @package enrol_meta + * @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; + +/** + * Meta course enrolment plugin. + * @author Petr Skoda + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_meta_plugin extends enrol_plugin { + + /** + * Returns localised name of enrol instance + * + * @param object $instance (null is accepted too) + * @return string + */ + public function get_instance_name($instance) { + global $DB; + + if (empty($instance)) { + $enrol = $this->get_name(); + return get_string('pluginname', 'enrol_'.$enrol); + } else if (empty($instance->name)) { + $enrol = $this->get_name(); + return get_string('pluginname', 'enrol_'.$enrol) . ' (' . format_string($DB->get_field('course', 'fullname', array('id'=>$instance->customint1))) . ')'; + } else { + return format_string($instance->name); + } + } + + /** + * 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_candidate_link($courseid) { + if (!has_capability('moodle/course:enrolconfig', get_context_instance(CONTEXT_COURSE, $courseid, MUST_EXIST))) { + return NULL; + } + // multiple instances supported - multiple parent courses linked + return new moodle_url('/enrol/meta/addinstance.php', array('id'=>$courseid)); + } + + + /** + * Called after updating/inserting course. + * + * @param bool $inserted true if course just inserted + * @param object $course + * @param object $data form data + * @return void + */ + public function course_updated($inserted, $course, $data) { + global $CFG; + + if (!$inserted) { + // sync cohort enrols + require_once("$CFG->dirroot/enrol/meta/locallib.php"); + enrol_meta_sync($course->id); + } else { + // cohorts are never inserted automatically + } + + } + + /** + * Called for all enabled enrol plugins that returned true from is_cron_required(). + * @return void + */ + public function cron() { + global $CFG; + + // purge all roles if meta sync disabled, those can be recreated later here in cron + if (!enrol_is_enabled('meta')) { + role_unassign_all(array('component'=>'meta_enrol')); + return; + } + + require_once("$CFG->dirroot/enrol/meta/locallib.php"); + enrol_meta_sync(); + } +} + diff --git a/enrol/meta/locallib.php b/enrol/meta/locallib.php new file mode 100644 index 00000000000..bd4d54e67a5 --- /dev/null +++ b/enrol/meta/locallib.php @@ -0,0 +1,317 @@ +. + +/** + * Local stuff for meta course enrolment plugin. + * + * @package enrol_meta + * @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; + +/** + * Event handler for meta enrolment plugin. + * + * We try to keep everything in sync via listening to events, + * it may fail sometimes, so we always do a full sync in cron too. + */ +class enrol_meta_handler { + public function role_assigned($ra) { + global $DB; + + if (!enrol_is_enabled('meta')) { + return true; + } + + // prevent circular dependencies - we can not sync meta roles recursively + if ($ra->component === 'enrol_meta') { + return true; + } + + //only course level roles are interesting + $parentcontext = get_context_instance_by_id($ra->contextid); + if ($parentcontext->contextlevel != CONTEXT_COURSE) { + return true; + } + + // does anything want to sync with this parent? + if (!$enrols = $DB->get_records('enrol', array('customint1'=>$parentcontext->instanceid, 'enrol'=>'meta'), 'id ASC')) { + return true; + } + + // make sure the role sync is not prevented + $plugin = enrol_get_plugin('meta'); + if ($disabled = $plugin->get_config('nosyncroleids')) { + if (in_array($ra->roleid, explode(',', $disabled))) { + continue; + } + } + + foreach ($enrols as $enrol) { + // Is the user enrolled? We want to sync only really enrolled users + if (!$DB->record_exists('user_enrolments', array('userid'=>$ra->userid, 'enrolid'=>$enrol->id))) { + continue; + } + $context = get_context_instance(CONTEXT_COURSE, $enrol->courseid); + + // just try to assign role, no problem if role assignment already exists + role_assign($ra->roleid, $ra->userid, $context->id, 'enrol_meta', $enrol->id); + } + + return true; + } + + public function role_unassigned($ra) { + global $DB; + + //note: do not test if plugin enabled, we want to keep removing previous roles + + // prevent circular dependencies - we can not sync meta roles recursively + if ($ra->component === 'enrol_meta') { + return true; + } + + // only course level roles are interesting + $parentcontext = get_context_instance_by_id($ra->contextid); + if ($parentcontext->contextlevel != CONTEXT_COURSE) { + return true; + } + + // does anything want to sync with this parent? + if (!$enrols = $DB->get_records('enrol', array('customint1'=>$parentcontext->instanceid, 'enrol'=>'meta'), 'id ASC')) { + return true; + } + + //note: do not check 'nosyncroleids', somebody might have just enabled it, we want to get rid of nosync roles gradually + + foreach ($enrols as $enrol) { + // Is the user enrolled? We want to sync only really enrolled users + if (!$DB->record_exists('user_enrolments', array('userid'=>$ra->userid, 'enrolid'=>$enrol->id))) { + continue; + } + $context = get_context_instance(CONTEXT_COURSE, $enrol->courseid); + + // now make sure the user does not have the role through some other enrol plugin + $params = array('contextid'=>$ra->contextid, 'roleid'=>$ra->roleid, 'userid'=>$ra->userid); + if ($DB->record_exists_select('role_assignments', "contextid = :contextid AND roleid = :roleid AND userid = :userid AND component <> 'enrol_meta'", $params)) { + continue; + } + + // unassing role, there is no other role assignment in parent course + role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $enrol->id); + } + + return true; + } + + public function user_enrolled($ue) { + global $DB; + + if (!enrol_is_enabled('meta')) { + return true; + } + + // does anything want to sync with this parent? + if (!$enrols = $DB->get_records('enrol', array('customint1'=>$ue->courseid, 'enrol'=>'meta'), 'id ASC')) { + return true; + } + + $plugin = enrol_get_plugin('meta'); + foreach ($enrols as $enrol) { + // no problem if already enrolled + $plugin->enrol_user($enrol, $ue->userid); + } + + return true; + } + + public function user_unenrolled($ue) { + global $DB; + + //note: do not test if plugin enabled, we want to keep removing previously linked courses + + // look for unenrolment candidates - it may be possible that user has multiple enrolments... + $sql = "SELECT DISTINCT e.* + FROM {enrol} e + JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid) + JOIN {enrol} pe ON (pe.courseid = e.customint1 AND pe.enrol <> 'meta' AND pe.courseid = :courseid) + LEFT JOIN {user_enrolments} pue ON (pue.enrolid = pe.id AND pue.userid = ue.userid) + WHERE pue.id IS NULL"; + $params = array('courseid'=>$ue->courseid, 'userid'=>$ue->userid); + + if (!$enrols = $DB->get_records_sql($sql, $params)) { + return true; + } + + $plugin = enrol_get_plugin('meta'); + foreach ($enrols as $enrol) { + $plugin->unenrol_user($enrol, $ue->userid); + } + + return true; + } + + public function course_deleted($course) { + global $DB; + + //note: do not test if plugin enabled, we want to keep removing previously linked courses + + // does anything want to sync with this parent? + if (!$enrols = $DB->get_records('enrol', array('customint1'=>$parentcontext->instanceid, 'enrol'=>'meta'), 'id ASC')) { + return true; + } + + $plugin = enrol_get_plugin('meta'); + foreach ($enrols as $enrol) { + //unenrol all users + $ues = $DB->get_records_sql('user_enrolments', array('courseid'=>$enrol->courseid, 'enrolid'=>$enrol->id)); + foreach ($ues as $ue) { + $plugin->unenrol_user($enrol, $ue->userid); + } + $ues->close(); + } + + return true; + } +} + +/** + * Sync all meta course links. + * @param int $courseid one course, empty mean all + * @return void + */ +function enrol_meta_sync($courseid = NULL) { + global $CFG, $DB; + + // unfortunately this may take a loooong time + @set_time_limit(0); //if this fails during upgrade we can continue from cron, no big deal + + $meta = enrol_get_plugin('meta'); + + $onecourse = $courseid ? "AND e.courseid = :courseid" : ""; + + // iterate through all not enrolled yet users + if (enrol_is_enabled('meta')) { + list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e00'); + $onecourse = ""; + if ($courseid) { + $params['courseid'] = $courseid; + $onecourse = "AND e.courseid = :courseid"; + } + $sql = "SELECT pue.userid, e.id AS enrolid + FROM {user_enrolments} pue + JOIN {enrol} pe ON (pe.id = pue.enrolid AND pe.enrol <> 'meta' AND pe.enrol $enabled ) + JOIN {enrol} e ON (e.customint1 = pe.courseid AND e.enrol = 'meta' AND e.status = :statusenabled $onecourse) + LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = pue.userid) + WHERE ue.id IS NULL"; + $params['statusenabled'] = ENROL_INSTANCE_ENABLED; + $params['courseid'] = $courseid; + + $rs = $DB->get_recordset_sql($sql, $params); + $instances = array(); //cache + foreach($rs as $ue) { + if (!isset($instances[$ue->enrolid])) { + $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid)); + } + $meta->enrol_user($instances[$ue->enrolid], $ue->userid); + } + $rs->close(); + unset($instances); + } + + // unenrol as necessary - ignore enabled flag, we want to get rid of all + $sql = "SELECT ue.userid, e.id AS enrolid + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse) + LEFT JOIN (SELECT xue.userid, xe.courseid + FROM {enrol} xe + JOIN {user_enrolments} xue ON (xue.enrolid = xe.id) + ) pue ON (pue.courseid = e.customint1 AND pue.userid = ue.userid) + WHERE pue.courseid IS NULL"; + //TODO: this may use a bit of SQL optimisation + $rs = $DB->get_recordset_sql($sql, array('courseid'=>$courseid)); + $instances = array(); //cache + foreach($rs as $ue) { + if (!isset($instances[$ue->enrolid])) { + $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid)); + } + $meta->unenrol_user($instances[$ue->enrolid], $ue->userid); + } + $rs->close(); + unset($instances); + + // now assign all necessary roles + if (enrol_is_enabled('meta')) { + $enabled = explode(',', $CFG->enrol_plugins_enabled); + foreach($enabled as $k=>$v) { + if ($v === 'meta') { + continue; // no meta sync of meta roles + } + $enabled[$k] = 'enrol_'.$v; + } + $enabled[] = $DB->sql_empty(); // manual assignments are replicated too + + list($enabled, $params) = $DB->get_in_or_equal($enabled, SQL_PARAMS_NAMED, 'e00'); + $sql = "SELECT DISTINCT pra.roleid, pra.userid, c.id AS contextid, e.id AS enrolid + FROM {role_assignments} pra + JOIN {context} pc ON (pc.id = pra.contextid AND pc.contextlevel = :coursecontext AND pra.component $enabled) + JOIN {enrol} e ON (e.customint1 = pc.instanceid AND e.enrol = 'meta' AND e.status = :statusenabled $onecourse) + JOIN {context} c ON (c.contextlevel = pc.contextlevel AND c.instanceid = e.courseid) + LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.userid = pra.userid AND ra.roleid = pra.itemid AND ra.itemid = e.id AND ra.component = 'enrol_meta') + WHERE ra.id IS NULL"; + $params['statusenabled'] = ENROL_INSTANCE_ENABLED; + $params['coursecontext'] = CONTEXT_COURSE; + $params['courseid'] = $courseid; + + if ($ignored = $meta->get_config('nosyncroleids')) { + list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'i00', false); + $params = array_merge($params, $xparams); + $sql = "$sql AND pra.roleid $notignored"; + } + + $rs = $DB->get_recordset_sql($sql, $params); + foreach($rs as $ra) { + role_assign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->enrolid); + } + $rs->close(); + } + + // remove unwanted roles - include ignored roles and disabled plugins too + $params = array('coursecontext' => CONTEXT_COURSE, 'courseid' => $courseid); + if ($ignored = $meta->get_config('nosyncroleids')) { + list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'i00', false); + $params = array_merge($params, $xparams); + $notignored = "AND pra.roleid $notignored"; + } else { + $notignored = ""; + } + $sql = "SELECT ra.roleid, ra.userid, ra.contextid, ra.itemid + FROM {role_assignments} ra + JOIN {enrol} e ON (e.id = ra.itemid AND ra.component = 'enrol_meta' AND e.enrol = 'meta' $onecourse) + JOIN {context} pc ON (pc.instanceid = e.customint1 AND pc.contextlevel = :coursecontext) + LEFT JOIN {role_assignments} pra ON (pra.contextid = pc.id AND pra.userid = ra.userid AND pra.roleid = ra.roleid AND pra.component <> 'enrol_meta' $notignored) + WHERE pra.id IS NULL"; + + $rs = $DB->get_recordset_sql($sql, $params); + foreach($rs as $ra) { + role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->itemid); + } + $rs->close(); + +} diff --git a/enrol/meta/settings.php b/enrol/meta/settings.php new file mode 100644 index 00000000000..3402f582c71 --- /dev/null +++ b/enrol/meta/settings.php @@ -0,0 +1,41 @@ +. + +/** + * Meta enrolment plugin settings and presets. + * + * @package enrol_meta + * @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_meta_settings', '', get_string('pluginname_desc', 'enrol_meta'))); + + if (!during_initial_install()) { + $allroles = array(); + foreach (get_all_roles() as $role) { + $rolename = strip_tags(format_string($role->name)) . ' ('. $role->shortname . ')'; + $allroles[$role->id] = $rolename; + } + $settings->add(new admin_setting_configmultiselect('enrol_meta/nosyncroleids', get_string('nosyncroleids', 'enrol_meta'), get_string('nosyncroleids_desc', 'enrol_meta'), array(), $allroles)); + } +} diff --git a/enrol/meta/version.php b/enrol/meta/version.php new file mode 100644 index 00000000000..7dc73631272 --- /dev/null +++ b/enrol/meta/version.php @@ -0,0 +1,27 @@ +. + +/** + * Meta link enrolment plugin version specification. + * + * @package enrol_meta + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$plugin->version = 2010061500; +$plugin->cron = 60; \ No newline at end of file diff --git a/enrol/mnet/enrol.php b/enrol/mnet/enrol.php index 388c875df18..67fdf3cfa4d 100644 --- a/enrol/mnet/enrol.php +++ b/enrol/mnet/enrol.php @@ -352,9 +352,7 @@ class enrolment_plugin_mnet { // Are we a *real* user or the shady MNET Daemon? // require_capability('moodle/role:assign', $context, NULL, false); - if (!role_unassign(0, $userrecord->id, 0, $context->id)) { - throw new mnet_exception(5015, 'couldnotunenrol', 'enrol_mnet'); - } + role_unassign_all(array('userid'=>$userrecord->id, 'contextiod'=>$context->id, 'component'=>'enrol_mnet'), true, true); return true; } diff --git a/enrol/otherusers.php b/enrol/otherusers.php new file mode 100644 index 00000000000..401e12333e9 --- /dev/null +++ b/enrol/otherusers.php @@ -0,0 +1,91 @@ +. + +/** + * List and modify users that are not enrolled but still have a role in course. + * + * @package core + * @subpackage enrol + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../config.php'); + +$id = required_param('id', PARAM_INT); // course id +$action = optional_param('action', '', PARAM_ACTION); +$confirm = optional_param('confirm', 0, PARAM_BOOL); + +$ifilter = optional_param('ifilter', 0, PARAM_INT); // only one instance +$page = optional_param('page', 0, PARAM_INT); +$perpage = optional_param('perpage', 20, PARAM_INT); +$sort = optional_param('sort', 'lastname', PARAM_ALPHA); +$dir = optional_param('dir', 'ASC', PARAM_ALPHA); + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +require_login($course); +require_capability('moodle/role:assign', $context); + +if ($course->id == SITEID) { + redirect("$CFG->wwwroot/"); +} + +$instances = enrol_get_instances($course->id, true); +$plugins = enrol_get_plugins(true); +$inames = array(); +foreach ($instances as $k=>$i) { + if (!isset($plugins[$i->enrol])) { + // weird, some broken stuff in plugin + unset($instances[$k]); + continue; + } + $inames[$k] = $plugins[$i->enrol]->get_instance_name($i); +} + +// validate paging params +if ($ifilter != 0 and !isset($instances[$ifilter])) { + $ifilter = 0; +} +if ($perpage < 3) { + $perpage = 3; +} +if ($page < 0) { + $page = 0; +} +if (!in_array($dir, array('ASC', 'DESC'))) { + $dir = 'ASC'; +} +if (!in_array($sort, array('firstname', 'lastname', 'email', 'lastseen'))) { + $dir = 'lastname'; +} + +$PAGE->set_url('/enrol/notenrolled.php', array('id'=>$course->id, 'page'=>$page, 'sort'=>$sort, 'dir'=>$dir, 'perpage'=>$perpage, 'ifilter'=>$ifilter)); +$PAGE->set_pagelayout('admin'); + +//lalala- nav hack +navigation_node::override_active_url(new moodle_url('/enrol/otherusers.php', array('id'=>$course->id))); + +echo $OUTPUT->header(); + +//TODO: MDL-22854 add some new role related UI for users that are not enrolled but still got a role somehow in this course context + +notify('This page is not implemented yet, sorry. See MDL-21782 in our tracker for more information.'); + +echo $OUTPUT->single_button(new moodle_url('/admin/roles/assign.php', array('contextid'=>$context->id)), 'Continue to old Assign roles UI'); + +echo $OUTPUT->footer(); diff --git a/enrol/paypal/enrol.php b/enrol/paypal/enrol.php index 0be07cbb57a..67c9f0383fa 100644 --- a/enrol/paypal/enrol.php +++ b/enrol/paypal/enrol.php @@ -1,9 +1,6 @@ dirroot/enrol/enrol.class.php"); - - class enrolment_plugin_paypal { diff --git a/enrol/paypal/ipn.php b/enrol/paypal/ipn.php index 33a5153b0fb..4bab5676020 100644 --- a/enrol/paypal/ipn.php +++ b/enrol/paypal/ipn.php @@ -93,7 +93,7 @@ // and notify admin if ($data->payment_status != "Completed" and $data->payment_status != "Pending") { - role_unassign(0, $data->userid, 0, $context->id); + role_unassign_all(array('userid'=>$data->userid, 'contextid'=>$context->id, 'component'=>'enrol_paypal'), true, true); message_paypal_error_to_admin("Status not completed or pending. User unenrolled from course", $data); die; } diff --git a/enrol/paypal/return.php b/enrol/paypal/return.php index 80c207280f2..6d2f4ce6db3 100644 --- a/enrol/paypal/return.php +++ b/enrol/paypal/return.php @@ -25,7 +25,7 @@ $destination = "$CFG->wwwroot/course/view.php?id=$course->id"; } - if (has_capability('moodle/course:participate', $context)) { + if (is_enrolled($context, NULL, '', true)) { // TODO: use real paypal check redirect($destination, get_string('paymentthanks', '', $course->fullname)); } else { /// Somehow they aren't enrolled yet! :-( diff --git a/enrol/self/addinstance.php b/enrol/self/addinstance.php new file mode 100644 index 00000000000..c5ce3fab3a6 --- /dev/null +++ b/enrol/self/addinstance.php @@ -0,0 +1,43 @@ +. + +/** + * Adds new instance of enrol_self to specified course. + * + * @package enrol_self + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../config.php'); + +$id = required_param('id', PARAM_INT); // course id + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +require_login($course); +require_capability('moodle/course:enrolconfig', $context); +require_sesskey(); + +$enrol = enrol_get_plugin('self'); + +if ($enrol->get_candidate_link($course->id)) { + $enrol->add_default_instance($course); +} + +redirect(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); diff --git a/enrol/self/db/access.php b/enrol/self/db/access.php new file mode 100644 index 00000000000..8703f9a9580 --- /dev/null +++ b/enrol/self/db/access.php @@ -0,0 +1,52 @@ + array( + + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + ) + ), + + 'enrol/self:manage' => array( + + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + ) + ), + + 'enrol/self:unenrolself' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'student' => CAP_ALLOW, + ) + ), + + 'enrol/self:unenrol' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + ) + ), + +); + + diff --git a/enrol/self/db/install.php b/enrol/self/db/install.php new file mode 100644 index 00000000000..99f50676405 --- /dev/null +++ b/enrol/self/db/install.php @@ -0,0 +1,10 @@ +sendcoursewelcomemessage)) { + set_config('sendcoursewelcomemessage', $CFG->sendcoursewelcomemessage, 'enrol_self'); + unset_config('sendcoursewelcomemessage'); + } +} diff --git a/enrol/self/lang/en/enrol_self.php b/enrol/self/lang/en/enrol_self.php new file mode 100644 index 00000000000..c645aaf2fb7 --- /dev/null +++ b/enrol/self/lang/en/enrol_self.php @@ -0,0 +1,63 @@ +. + +/** + * Strings for component 'enrol_self', language 'en', branch 'MOODLE_20_STABLE' + * + * @package enrol_self + * @copyright 2010 onwards Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['defaultrole'] = 'Default role assignment'; +$string['defaultrole_desc'] = 'Select role which should be assigned to users during self enrolment'; +$string['enrolenddate'] = 'End date'; +$string['enrolenddaterror'] = 'Enrolment end date cannot be earlier than start date'; +$string['enrolme'] = 'Enrol me'; +$string['enrolperiod'] = 'Enrolment period'; +$string['enrolperiod_desc'] = 'Default length of the enrolment period (in seconds).'; //TODO: fixme +$string['enrolstartdate'] = 'Start date'; +$string['groupkey'] = 'Use group enrolment keys'; +$string['groupkey_desc'] = 'Use group enrolment keys by default.'; +$string['password'] = 'Enrolment key'; +$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'] = 'Self enrolment'; +$string['pluginname_desc'] = 'The self 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 enrolmnet 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 prevent removing of enrolment key from existing courses.'; +$string['role'] = 'Assign role'; +$string['self:config'] = 'Configure self enrol instances'; +$string['self:manage'] = 'Manage enrolled users'; +$string['self:unenrol'] = 'Unenrol users from course'; +$string['self:unenrolself'] = 'Unenrol self from the course'; +$string['sendcoursewelcomemessage'] = 'Send course welcome message'; +$string['sendcoursewelcomemessage_desc'] = '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'] = 'Allow self enrolments'; +$string['status_desc'] = 'Allow users to self enrol into course by default.'; +$string['unenrolselfconfirm'] = 'Do you really want to unenrol yourself from course "{$a}"?'; +$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}'; diff --git a/enrol/self/lib.php b/enrol/self/lib.php new file mode 100644 index 00000000000..4383537fbaf --- /dev/null +++ b/enrol/self/lib.php @@ -0,0 +1,433 @@ +. + +/** + * Self enrolment plugin. + * + * @package enrol_self + * @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_self_plugin extends enrol_plugin { + + /** + * Returns localised name of enrol instance + * + * @param object $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, get_context_instance(CONTEXT_COURSE, $instance->courseid)) . ')'; + } 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; + } + + /** + * 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_candidate_link($courseid) { + if (!has_capability('moodle/course:enrolconfig', get_context_instance(CONTEXT_COURSE, $courseid, MUST_EXIST))) { + return NULL; + } + // multiple instances supported - different roles with different password + return new moodle_url('/enrol/self/addinstance.php', array('sesskey'=>sesskey(), 'id'=>$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; + } + + require_once("$CFG->dirroot/enrol/self/locallib.php"); + $form = new enrol_self_enrol_form(NULL, $instance); + $instanceid = optional_param('instance', 0, PARAM_INT); + + if ($instance->id == $instanceid) { + if ($data = $form->get_data()) { + $enrol = enrol_get_plugin('self'); + if ($instance->enrolperiod) { + $timestart = time(); + $tineend = $timestart + $instance->enrolperiod; + } else { + $timestart = 0; + $tineend = 0; + } + + $this->enrol_user($instance, $USER->id, $instance->roleid, $timestart, $tineend); + add_to_log($instance->courseid, 'course', 'enrol', '../enrol/users.php?id='.$instance->courseid, $instance->courseid); //there should be userid somewhere! + // send welcome + if ($this->get_config('sendcoursewelcomemessage')) { + $this->email_welcome_message($instance, $USER); + } + } + } + + ob_start(); + $form->display(); + $output = ob_get_clean(); + + return $OUTPUT->box($output); + } + + /** + * Adds enrol instance UI to course edit form + * + * @param object $instance enrol instance or null if does not exist yet + * @param MoodleQuickForm $mform + * @param object $data + * @param object $context context of existing course or parent category if course does not exist + * @return void + */ + public function course_edit_form($instance, MoodleQuickForm $mform, $data, $context) { + + $i = isset($instance->id) ? $instance->id : 0; + $plugin = enrol_get_plugin('self'); + $header = $plugin->get_instance_name($instance); + $config = has_capability('enrol/self:config', $context); + + $mform->addElement('header', 'enrol_self_header_'.$i, $header); + + + $options = array(ENROL_INSTANCE_ENABLED => get_string('yes'), + ENROL_INSTANCE_DISABLED => get_string('no')); + $mform->addElement('select', 'enrol_self_status_'.$i, get_string('status', 'enrol_self'), $options); + $mform->setDefault('enrol_self_status_'.$i, $this->get_config('status')); + $mform->setAdvanced('enrol_self_status_'.$i, $this->get_config('status_adv')); + if (!$config) { + $mform->hardFreeze('enrol_self_status_'.$i); + } + + + $mform->addElement('passwordunmask', 'enrol_self_password_'.$i, get_string('password', 'enrol_self')); + if (!$config) { + $mform->hardFreeze('enrol_self_password_'.$i); + } else { + $mform->disabledIf('enrol_self_password_'.$i, 'enrol_self_status_'.$i, 'noteq', ENROL_INSTANCE_ENABLED); + } + + + $options = array(1 => get_string('yes'), + 0 => get_string('no')); + $mform->addElement('select', 'enrol_self_customint1_'.$i, get_string('groupkey', 'enrol_self'), $options); + $mform->setDefault('enrol_self_customint1_'.$i, $this->get_config('groupkey')); + $mform->setAdvanced('enrol_self_customint1_'.$i, $this->get_config('groupkey_adv')); + if (!$config) { + $mform->hardFreeze('enrol_self_customint1_'.$i); + } else { + $mform->disabledIf('enrol_self_customint1_'.$i, 'enrol_self_status_'.$i, 'noteq', ENROL_INSTANCE_ENABLED); + } + + + if ($instance) { + $roles = get_default_enrol_roles($context, $instance->roleid); + } else { + $roles = get_default_enrol_roles($context, $this->get_config('roleid')); + } + $mform->addElement('select', 'enrol_self_roleid_'.$i, get_string('role', 'enrol_self'), $roles); + $mform->setDefault('enrol_self_roleid_'.$i, $this->get_config('roleid')); + $mform->setAdvanced('enrol_self_roleid_'.$i, $this->get_config('roleid_adv')); + if (!$config) { + $mform->hardFreeze('enrol_self_roleid_'.$i); + } else { + $mform->disabledIf('enrol_self_roleid_'.$i, 'enrol_self_status_'.$i, 'noteq', ENROL_INSTANCE_ENABLED); + } + + + $mform->addElement('duration', 'enrol_self_enrolperiod_'.$i, get_string('enrolperiod', 'enrol_self'), array('optional' => true, 'defaultunit' => 86400)); + $mform->setDefault('enrol_self_enrolperiod_'.$i, $this->get_config('enrolperiod')); + $mform->setAdvanced('enrol_self_enrolperiod_'.$i, $this->get_config('enrolperiod_adv')); + if (!$config) { + $mform->hardFreeze('enrol_self_enrolperiod_'.$i); + } else { + $mform->disabledIf('enrol_self_enrolperiod_'.$i, 'enrol_self_status_'.$i, 'noteq', ENROL_INSTANCE_ENABLED); + } + + + $mform->addElement('date_selector', 'enrol_self_enrolstartdate_'.$i, get_string('enrolstartdate', 'enrol_self'), array('optional' => true)); + $mform->setDefault('enrol_self_enrolstartdate_'.$i, 0); + $mform->setAdvanced('enrol_self_enrolstartdate_'.$i, 1); + if (!$config) { + $mform->hardFreeze('enrol_self_enrolstartdate_'.$i); + } else { + $mform->disabledIf('enrol_self_enrolstartdate_'.$i, 'enrol_self_status_'.$i, 'noteq', ENROL_INSTANCE_ENABLED); + } + + + $mform->addElement('date_selector', 'enrol_self_enrolenddate_'.$i, get_string('enrolenddate', 'enrol_self'), array('optional' => true)); + $mform->setDefault('enrol_self_enrolenddate_'.$i, 0); + $mform->setAdvanced('enrol_self_enrolenddate_'.$i, 1); + if (!$config) { + $mform->hardFreeze('enrol_self_enrolenddate_'.$i); + } else { + $mform->disabledIf('enrol_self_enrolenddate_'.$i, 'enrol_self_status_'.$i, 'noteq', ENROL_INSTANCE_ENABLED); + } + + + // now add all values from enrol table + if ($instance) { + foreach($instance as $key=>$val) { + $data->{'enrol_self_'.$key.'_'.$i} = $val; + } + } + } + + + /** + * Validates course edit form data + * + * @param object $instance enrol instance or null if does not exist yet + * @param array $data + * @param object $context context of existing course or parent category if course does not exist + * @return array errors array + */ + public function course_edit_validation($instance, array $data, $context) { + $errors = array(); + + if (!has_capability('enrol/self:config', $context)) { + // we are going to ignore the data later anyway, they would not be able to fix the form anyway + return $errors; + } + + $i = isset($instance->id) ? $instance->id : 0; + + $password = empty($data['enrol_self_password_'.$i]) ? '' : $data['enrol_self_password_'.$i]; + $checkpassword = false; + + if ($instance) { + if ($data['enrol_self_status_'.$i] == ENROL_INSTANCE_ENABLED) { + if ($instance->password !== $password) { + $checkpassword = true; + } + } + } else { + if ($data['enrol_self_status_'.$i] == ENROL_INSTANCE_ENABLED) { + $checkpassword = true; + } + } + + if ($checkpassword) { + $require = $this->get_config('requirepassword'); + $policy = $this->get_config('usepasswordpolicy'); + if ($require and empty($password)) { + $errors['enrol_self_password_'.$i] = get_string('required'); + } else if ($policy) { + $errmsg = '';//prevent eclipse warning + if (!check_password_policy($password, $errmsg)) { + $errors['enrol_self_password_'.$i] = $errmsg; + } + } + } + + if ($data['enrol_self_status_'.$i] == ENROL_INSTANCE_ENABLED) { + if (!empty($data['enrol_self_enrolenddate_'.$i]) and $data['enrol_self_enrolenddate_'.$i] < $data['enrol_self_enrolstartdate_'.$i]) { + $errors['enrol_self_enrolenddate_'.$i] = get_string('enrolenddaterror', 'enrol_self'); + } + } + + return $errors; + } + + + /** + * Called after updating/inserting course. + * + * @param bool $inserted true if course just inserted + * @param object $course + * @param object $data form data + * @return void + */ + public function course_updated($inserted, $course, $data) { + global $DB; + + $context = get_context_instance(CONTEXT_COURSE, $course->id); + + if (has_capability('enrol/self:config', $context)) { + if ($inserted) { + if (isset($data->enrol_self_status_0)) { + $fields = array('status'=>$data->enrol_self_status_0); + if ($fields['status'] == ENROL_INSTANCE_ENABLED) { + $fields['password'] = $data->enrol_self_password_0; + $fields['customint1'] = $data->enrol_self_customint1_0; + $fields['roleid'] = $data->enrol_self_roleid_0; + $fields['enrolperiod'] = $data->enrol_self_enrolperiod_0; + $fields['enrolstartdate'] = $data->enrol_self_enrolstartdate_0; + $fields['enrolenddate'] = $data->enrol_self_enrolenddate_0; + } else { + if ($this->get_config('requirepassword')) { + // make sure some password is set after enabling this plugin + $fields['password'] = generate_password(20); + } + $fields['customint1'] = $this->get_config('groupkey'); + $fields['roleid'] = $this->get_config('roleid'); + $fields['enrolperiod'] = $this->get_config('enrolperiod'); + $fields['enrolstartdate'] = 0; + $fields['enrolenddate'] = 0; + } + $this->add_instance($course, $fields); + } + + } else { + $instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'self')); + foreach ($instances as $instance) { + $i = $instance->id; + + if (isset($data->{'enrol_self_status_'.$i})) { + $instance->status = $data->{'enrol_self_status_'.$i}; + $instance->timemodified = time(); + if ($instance->status == ENROL_INSTANCE_ENABLED) { + $instance->password = $data->{'enrol_self_password_'.$i}; + $instance->customint1 = $data->{'enrol_self_customint1_'.$i}; + $instance->roleid = $data->{'enrol_self_roleid_'.$i}; + $instance->enrolperiod = $data->{'enrol_self_enrolperiod_'.$i}; + $instance->enrolstartdate = $data->{'enrol_self_enrolstartdate_'.$i}; + $instance->enrolenddate = $data->{'enrol_self_enrolenddate_'.$i}; + } + $DB->update_record('enrol', $instance); + } + } + } + + } else { + if ($inserted) { + if ($this->get_config('defaultenrol')) { + $this->add_default_instance($course); + } + } else { + // bad luck, user can not change anything + } + } + } + + /** + * Add new instance of enrol plugin with default settings. + * @param object $course + * @return int id of new instance + */ + public function add_default_instance($course) { + global $DB; + + $exists = $DB->record_exists('enrol', array('courseid'=>$course->id, 'enrol'=>'self')); + + $fields = array('customint1'=>$this->get_config('groupkey'), 'enrolperiod'=>$this->get_config('enrolperiod', 0), 'roleid'=>$this->get_config('roleid', 0)); + + $fields['status'] = $exists ? ENROL_INSTANCE_DISABLED : $this->get_config('status'); + + if ($this->get_config('requirepassword')) { + $fields['password'] = generate_password(20); + } + + return $this->add_instance($course, $fields); + } + + /** + * Send welcome email to specified user + * + * @param object $instance + * @param object $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); + + if (!empty($instance->customtext1)) { + //note: there is no gui for this yet, do we really need it? + $message = formaat_string($instance->customtext1); + } else { + $a = new object(); + $a->coursename = format_string($course->fullname); + $a->profileurl = "$CFG->wwwroot/user/view.php?id=$user->id&course=$course->id"; + $message = get_string("welcometocoursetext", 'enrol_self', $a); + } + + $subject = get_string('welcometocourse', 'enrol_self', format_string($course->fullname)); + + $context = get_context_instance(CONTEXT_COURSE, $course->id); + $rusers = null; + if (!empty($CFG->coursecontact)) { + $croles = explode(',', $CFG->coursecontact); + $rusers = get_role_users($croles, $context, true, '', 'r.sortorder ASC, u.lastname ASC'); + } + if ($rusers) { + $contact = reset($rusers); + } else { + $contact = get_admin(); + } + + email_to_user($user, $contact, $subject, $message); + } +} + + diff --git a/enrol/self/locallib.php b/enrol/self/locallib.php new file mode 100644 index 00000000000..20a7da26e48 --- /dev/null +++ b/enrol/self/locallib.php @@ -0,0 +1,84 @@ +. + +/** + * Self enrol plugin implementation. + * + * @package enrol_self + * @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_self_enrol_form extends moodleform { + protected $instance; + + public function definition() { + $mform = $this->_form; + $instance = $this->_customdata; + $this->instance = $instance; + $plugin = enrol_get_plugin('self'); + + if ($instance->password) { + $heading = $plugin->get_instance_name($instance); + $mform->addElement('header', 'selfheader', $heading); + $mform->addElement('passwordunmask', 'enrolpassword', get_string('password', 'enrol_self')); + } else { + // nothing? + } + + $this->add_action_buttons(false, get_string('enrolme', 'enrol_self')); + + $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 ($instance->password) { + if ($data['enrolpassword'] !== $instance->password) { + if ($instance->customint1) { + //TODO: check groups + + } else { + $plugin = enrol_get_plugin('self'); + if ($plugin->get_config('showhint')) { + $textlib = textlib_get_instance(); + $hint = $textlib->substr($instance->password, 0, 1); + $errors['enrolpassword'] = get_string('passwordinvalidhint', 'enrol_self', $hint); + } else { + $errors['enrolpassword'] = get_string('passwordinvalid', 'enrol_self'); + } + } + } + } + + return $errors; + } +} \ No newline at end of file diff --git a/enrol/self/settings.php b/enrol/self/settings.php new file mode 100644 index 00000000000..050b2141fcd --- /dev/null +++ b/enrol/self/settings.php @@ -0,0 +1,79 @@ +. + +/** + * Self enrolment plugin settings and presets. + * + * @package enrol_self + * @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_self_settings', '', get_string('pluginname_desc', 'enrol_self'))); + + $settings->add(new admin_setting_configcheckbox('enrol_self/requirepassword', + get_string('requirepassword', 'enrol_self'), get_string('requirepassword_desc', 'enrol_self'), 0)); + + $settings->add(new admin_setting_configcheckbox('enrol_self/usepasswordpolicy', + get_string('usepasswordpolicy', 'enrol_self'), get_string('usepasswordpolicy_desc', 'enrol_self'), 0)); + + $settings->add(new admin_setting_configcheckbox('enrol_self/showhint', + get_string('showhint', 'enrol_self'), get_string('showhint_desc', 'enrol_self'), 0)); + + $settings->add(new admin_setting_configcheckbox('enrol_self/sendcoursewelcomemessage', + get_string('sendcoursewelcomemessage', 'enrol_self'), get_string('sendcoursewelcomemessage_desc', 'enrol_self'), 1)); + + + //--- enrol instance defaults ---------------------------------------------------------------------------- + $settings->add(new admin_setting_heading('enrol_self_defaults', + get_string('enrolinstancedefaults', 'admin'), get_string('enrolinstancedefaults_desc', 'admin'))); + + $settings->add(new admin_setting_configcheckbox('enrol_self/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_with_advanced('enrol_self/status', + get_string('status', 'enrol_self'), get_string('status_desc', 'enrol_self'), + array('value'=>ENROL_INSTANCE_DISABLED, 'adv'=>false), $options)); + + $options = array(1 => get_string('yes'), + 0 => get_string('no')); + $settings->add(new admin_setting_configselect_with_advanced('enrol_self/groupkey', + get_string('groupkey', 'enrol_self'), get_string('groupkey_desc', 'enrol_self'), + array('value'=>0, 'adv'=>true), $options)); + + if (!during_initial_install()) { + $options = get_default_enrol_roles(get_context_instance(CONTEXT_SYSTEM)); + $student = get_archetype_roles('student'); + $student = reset($student); + $settings->add(new admin_setting_configselect_with_advanced('enrol_self/roleid', + get_string('defaultrole', 'enrol_self'), get_string('defaultrole_desc', 'enrol_self'), + array('value'=>$student->id, 'adv'=>false), $options)); + } + + $settings->add(new admin_setting_configtext_with_advanced('enrol_self/enrolperiod', + get_string('enrolperiod', 'enrol_self'), get_string('enrolperiod_desc', 'enrol_self'), + array('value'=>0, 'adv'=>true), PARAM_INT)); + + +} diff --git a/enrol/self/unenrolself.php b/enrol/self/unenrolself.php new file mode 100644 index 00000000000..3e9ea09c3d0 --- /dev/null +++ b/enrol/self/unenrolself.php @@ -0,0 +1,58 @@ +. + +/** + * Self enrolment plugin - support for user self unenrolment. + * + * @package enrol_self + * @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'=>'self'), '*', MUST_EXIST); +$course = $DB->get_record('course', array('id'=>$instance->courseid), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +require_login($course); + +$plugin = enrol_get_plugin('self'); + +// security defined inside following function +if (!$plugin->get_unenrolself_link($instance)) { + redirect(new moodle_url('/course/view.php', array('id'=>$course->id))); +} + +$PAGE->set_url('/enrol/self/unenrolself.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); //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('unenrolselfconfirm', 'enrol_self', format_string($course->fullname)); +echo $OUTPUT->confirm($message, $yesurl, $nourl); +echo $OUTPUT->footer(); diff --git a/enrol/self/version.php b/enrol/self/version.php new file mode 100644 index 00000000000..b23cf7ba1dc --- /dev/null +++ b/enrol/self/version.php @@ -0,0 +1,26 @@ +. + +/** + * Self enrolment plugin version specification. + * + * @package enrol_self + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$plugin->version = 2010061600; diff --git a/enrol/users.php b/enrol/users.php new file mode 100644 index 00000000000..4d27d791958 --- /dev/null +++ b/enrol/users.php @@ -0,0 +1,518 @@ +. + +/** + * Main course enrolment management UI, this is not compatible with frontpage course. + * + * @package core + * @subpackage enrol + * @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("$CFG->dirroot/enrol/users_forms.php"); +require_once("$CFG->dirroot/group/lib.php"); + +$id = required_param('id', PARAM_INT); // course id +$action = optional_param('action', '', PARAM_ACTION); +$confirm = optional_param('confirm', 0, PARAM_BOOL); + +$ifilter = optional_param('ifilter', 0, PARAM_INT); // only one instance +$page = optional_param('page', 0, PARAM_INT); +$perpage = optional_param('perpage', 20, PARAM_INT); +$sort = optional_param('sort', 'lastname', PARAM_ALPHA); +$dir = optional_param('dir', 'ASC', PARAM_ALPHA); + + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +require_login($course); +require_capability('moodle/course:enrolreview', $context); + +if ($course->id == SITEID) { + redirect("$CFG->wwwroot/"); +} + +$managegroups = has_capability('moodle/course:managegroups', $context); +$instances = enrol_get_instances($course->id, true); +$plugins = enrol_get_plugins(true); +$inames = array(); +foreach ($instances as $k=>$i) { + if (!isset($plugins[$i->enrol])) { + // weird, some broken stuff in plugin + unset($instances[$k]); + continue; + } + $inames[$k] = $plugins[$i->enrol]->get_instance_name($i); +} + +// validate paging params +if ($ifilter != 0 and !isset($instances[$ifilter])) { + $ifilter = 0; +} +if ($perpage < 3) { + $perpage = 3; +} +if ($page < 0) { + $page = 0; +} +if (!in_array($dir, array('ASC', 'DESC'))) { + $dir = 'ASC'; +} +if (!in_array($sort, array('firstname', 'lastname', 'email', 'lastseen'))) { + $dir = 'lastname'; +} + +$PAGE->set_url('/enrol/users.php', array('id'=>$course->id, 'page'=>$page, 'sort'=>$sort, 'dir'=>$dir, 'perpage'=>$perpage, 'ifilter'=>$ifilter)); +$PAGE->set_pagelayout('admin'); + +//lalala- nav hack +navigation_node::override_active_url(new moodle_url('/enrol/users.php', array('id'=>$course->id))); + + +$allroles = get_all_roles(); +$allroles = role_fix_names($allroles, $context); +$assignable = get_assignable_roles($context, ROLENAME_ALIAS, false); // verifies unassign access control too +$allgroups = groups_get_all_groups($course->id); +foreach ($allgroups as $gid=>$group) { + $allgroups[$gid]->name = format_string($group->name); +} + +if ($action) { + switch ($action) { + case 'unenrol': + $ue = required_param('ue', PARAM_INT); + if (!$ue = $DB->get_record('user_enrolments', array('id'=>$ue))) { + break; + } + $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST); + if (!isset($instances[$ue->enrolid])) { + break; + } + $instance = $instances[$ue->enrolid]; + $plugin = $plugins[$instance->enrol]; + if (!$plugin->allow_unenrol($instance) or !has_capability("enrol/$instance->enrol:unenrol", $context)) { + break; + } + + if ($confirm and confirm_sesskey()) { + $plugin->unenrol_user($instance, $ue->userid); + redirect($PAGE->url); + + } else { + $yesurl = new moodle_url($PAGE->url, array('action'=>'unenrol', 'ue'=>$ue->id, 'confirm'=>1, 'sesskey'=>sesskey())); + $message = get_string('unenrolconfirm', 'enrol', array('user'=>fullname($user, true), 'course'=>format_string($course->fullname))); + $PAGE->set_title(get_string('unenrol', 'enrol')); + echo $OUTPUT->header(); + echo $OUTPUT->heading(get_string('unenrol', 'enrol')); + echo $OUTPUT->confirm($message, $yesurl, $PAGE->url); + echo $OUTPUT->footer(); + die; + } + break; + + case 'unassign': + $role = required_param('role', PARAM_INT); + $user = required_param('user', PARAM_INT); + if (!isset($assignable[$role])) { + break; + } + $role = $allroles[$role]; + $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST); + + if ($confirm and confirm_sesskey()) { + role_unassign($role->id, $user->id, $context->id, '', NULL); + redirect($PAGE->url); + + } else { + $yesurl = new moodle_url($PAGE->url, array('action'=>'unassign', 'role'=>$role->id, 'user'=>$user->id, 'confirm'=>1, 'sesskey'=>sesskey())); + $message = get_string('unassignconfirm', 'role', array('user'=>fullname($user, true), 'role'=>$role->localname)); + $PAGE->set_title(get_string('unassignarole', 'role', $role->localname)); + echo $OUTPUT->header(); + echo $OUTPUT->heading(get_string('unassignarole', 'role', $role->localname)); + echo $OUTPUT->confirm($message, $yesurl, $PAGE->url); + echo $OUTPUT->footer(); + die; + } + break; + + case 'assign': + $user = required_param('user', PARAM_INT); + $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST); + + if (!is_enrolled($context, $user)) { + break; // no roles without enrolments here in this script + } + + $mform = new enrol_users_assign_form(NULL, array('user'=>$user, 'course'=>$course, 'assignable'=>$assignable)); + + if ($mform->is_cancelled()) { + redirect($PAGE->url); + + } else if ($data = $mform->get_data()) { + if ($data->roleid) { + role_assign($data->roleid, $user->id, $context->id, '', NULL); + } + redirect($PAGE->url); + } + + $PAGE->set_title(get_string('assignroles', 'role')); + echo $OUTPUT->header(); + echo $OUTPUT->heading(get_string('assignroles', 'role')); + $mform->display(); + echo $OUTPUT->footer(); + die; + + case 'removemember': + $group = required_param('group', PARAM_INT); + $user = required_param('user', PARAM_INT); + if (!$managegroups) { + break; + } + if (!isset($allgroups[$group])) { + break; + } + $group = $allgroups[$group]; + $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST); + + if ($confirm and confirm_sesskey()) { + groups_remove_member($group, $user); + redirect($PAGE->url); + + } else { + $yesurl = new moodle_url($PAGE->url, array('action'=>'removemember', 'group'=>$group->id, 'user'=>$user->id, 'confirm'=>1, 'sesskey'=>sesskey())); + $message = get_string('removefromgroupconfirm', 'group', array('user'=>fullname($user, true), 'group'=>$group->name)); + $PAGE->set_title(get_string('removefromgroup', 'group', $group->name)); + echo $OUTPUT->header(); + echo $OUTPUT->heading(get_string('removefromgroup', 'group', $group->name)); + echo $OUTPUT->confirm($message, $yesurl, $PAGE->url); + echo $OUTPUT->footer(); + die; + } + break; + + case 'addmember': + $user = required_param('user', PARAM_INT); + $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST); + + if (!$managegroups) { + break; + } + if (!is_enrolled($context, $user)) { + break; // no roles without enrolments here in this script + } + + $mform = new enrol_users_addmember_form(NULL, array('user'=>$user, 'course'=>$course, 'allgroups'=>$allgroups)); + + if ($mform->is_cancelled()) { + redirect($PAGE->url); + + } else if ($data = $mform->get_data()) { + if ($data->groupid) { + groups_add_member($data->groupid, $user->id); + } + redirect($PAGE->url); + } + + $PAGE->set_title(get_string('addgroup', 'group')); + echo $OUTPUT->header(); + echo $OUTPUT->heading(get_string('addgroup', 'group')); + $mform->display(); + echo $OUTPUT->footer(); + die; + + case 'edit': + $ue = required_param('ue', PARAM_INT); + if (!$ue = $DB->get_record('user_enrolments', array('id'=>$ue))) { + break; + } + $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST); + if (!isset($instances[$ue->enrolid])) { + break; + } + $instance = $instances[$ue->enrolid]; + $plugin = $plugins[$instance->enrol]; + if (!$plugin->allow_unenrol($instance) or !has_capability("enrol/$instance->enrol:unenrol", $context)) { + break; + } + + $mform = new enrol_users_edit_form(NULL, array('user'=>$user, 'course'=>$course, 'ue'=>$ue)); + + if ($mform->is_cancelled()) { + redirect($PAGE->url); + + } else if ($data = $mform->get_data()) { + if (!isset($data->status)) { + $status = $ue->status; + } + $plugin->update_user_enrol($instance, $ue->userid, $data->status, $data->timestart, $data->timeend); + redirect($PAGE->url); + } + + $PAGE->set_title(fullname($user)); + echo $OUTPUT->header(); + echo $OUTPUT->heading(fullname($user)); + $mform->display(); + echo $OUTPUT->footer(); + die; + } +} + + +echo $OUTPUT->header(); +echo $OUTPUT->heading(get_string('enrolledusers', 'enrol')); +$PAGE->set_title(get_string('enrolledusers', 'enrol')); + +if ($ifilter) { + $instancessql = " = :ifilter"; + $params = array('ifilter'=>$ifilter); +} else { + if ($instances) { + list($instancessql, $params) = $DB->get_in_or_equal(array_keys($instances), SQL_PARAMS_NAMED); + } else { + // no enabled instances, oops, we should probably say something + $instancessql = "= :never"; + $params = array('never'=>-1); + } +} + +$sqltotal = "SELECT COUNT(DISTINCT u.id) + FROM {user} u + JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql) + JOIN {enrol} e ON (e.id = ue.enrolid)"; +$totalusers = $DB->count_records_sql($sqltotal, $params); + +$sql = "SELECT DISTINCT u.*, ul.timeaccess AS lastseen + FROM {user} u + JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql) + JOIN {enrol} e ON (e.id = ue.enrolid) + LEFT JOIN {user_lastaccess} ul ON (ul.courseid = e.courseid AND ul.userid = u.id)"; +if ($sort === 'firstname') { + $sql .= " ORDER BY u.firstname $dir, u.lastname $dir"; +} else if ($sort === 'lastname') { + $sql .= " ORDER BY u.lastname $dir, u.firstname $dir"; +} else if ($sort === 'email') { + $sql .= " ORDER BY u.email $dir, u.lastname $dir, u.firstname $dir"; +} else if ($sort === 'lastseen') { + $sql .= " ORDER BY ul.timeaccess $dir, u.lastname $dir, u.firstname $dir"; +} + +$pagingbar = new paging_bar($totalusers, $page, $perpage, $PAGE->url, 'page'); + +$users = $DB->get_records_sql($sql, $params, $page*$perpage, $perpage); + +$strfirstname = get_string('firstname'); +$strlastname = get_string('lastname'); +$stremail = get_string('email'); +$strlastseen = get_string('lastaccess'); + +if ($dir === 'ASC') { + $diricon = html_writer::empty_tag('img', array('alt'=>'', 'src'=>$OUTPUT->pix_url('t/down'))); + $newdir = 'DESC'; +} else { + $diricon = html_writer::empty_tag('img', array('alt'=>'', 'src'=>$OUTPUT->pix_url('t/up'))); + $newdir = 'ASC'; +} + +$table = new html_table(); +$table->head = array(); +if ($sort === 'firstname') { + $h = html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $strfirstname); + $h .= " $diricon / "; + $h .= html_writer::link(new moodle_url($PAGE->url, array('sort'=>'lastname')), $strlastname); +} else if ($sort === 'lastname') { + $newdir = ($dir === 'ASC') ? 'DESC' : 'ASC'; + $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'firstname')), $strfirstname); + $h .= " / "; + $h .= html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $strlastname); + $h .= " $diricon"; +} else { + $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'firstname')), $strfirstname); + $h .= " / "; + $h .= html_writer::link(new moodle_url($PAGE->url, array('sort'=>'lastname')), $strlastname); +} +$table->head[] = $h; +if ($sort === 'email') { + $h = html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $stremail); + $h .= " $diricon"; +} else { + $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'email')), $stremail); +} +$table->head[] = $h; +if ($sort === 'lastseen') { + $h = html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $strlastseen); + $h .= " $diricon"; +} else { + $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'lastseen')), $strlastseen); +} +$table->head[] = $h; +$table->head[] = get_string('roles', 'role'); +$table->head[] = get_string('groups', 'group'); +$table->head[] = get_string('enrolmentinstances', 'enrol'); + +$table->align = array('left', 'left', 'left', 'left', 'left', 'left'); +$table->width = "95%"; +foreach ($users as $user) { + $picture = $OUTPUT->user_picture($user, array('courseid'=>$course->id)); + + if ($user->lastseen) { + $strlastaccess = format_time(time() - $user->lastaccess); + } else { + $strlastaccess = get_string('never'); + } + $fullname = fullname($user, true); + + // get list of roles + $roles = array(); + $ras = get_user_roles($context, $user->id, true, 'c.contextlevel DESC, r.sortorder ASC'); + foreach ($ras as $ra) { + if ($ra->contextid != $context->id) { + if (!isset($roles[$ra->roleid])) { + $roles[$ra->roleid] = null; + } + // higher ras, course always takes precedence + continue; + } + if (isset($roles[$ra->roleid]) and $roles[$ra->roleid] === false) { + continue; + } + $roles[$ra->roleid] = ($ra->itemid == 0 and $ra->component === ''); + } + foreach ($roles as $rid=>$unassignable) { + if ($unassignable and isset($assignable[$rid])) { + $icon = html_writer::empty_tag('img', array('alt'=>get_string('unassignarole', 'role', $allroles[$rid]->localname), 'src'=>$OUTPUT->pix_url('t/delete'))); + $url = new moodle_url($PAGE->url, array('action'=>'unassign', 'role'=>$rid, 'user'=>$user->id)); + $roles[$rid] = $allroles[$rid]->localname . html_writer::link($url, $icon); + } else { + $roles[$rid] = $allroles[$rid]->localname; + } + } + $addrole = ''; + if ($assignable) { + foreach ($assignable as $rid=>$unused) { + if (!isset($roles[$rid])) { + //candidate for role assignment + $icon = html_writer::empty_tag('img', array('alt'=>get_string('assignroles', 'role'), 'src'=>$OUTPUT->pix_url('t/add'))); + $url = new moodle_url($PAGE->url, array('action'=>'assign', 'user'=>$user->id)); + $addrole .= html_writer::link($url, $icon); + break; + } + } + } + $roles = implode(', ', $roles); + if ($addrole) { + $roles = $roles . '
'.$addrole.'
'; + } + + $groups = array(); + $usergroups = groups_get_all_groups($course->id, $user->id, 0, 'g.id'); + foreach($usergroups as $gid=>$unused) { + $group = $allgroups[$gid]; + if ($managegroups) { + $icon = html_writer::empty_tag('img', array('alt'=>get_string('removefromgroup', 'group', $group->name), 'src'=>$OUTPUT->pix_url('t/delete'))); + $url = new moodle_url($PAGE->url, array('action'=>'removemember', 'group'=>$gid, 'user'=>$user->id)); + $groups[] = $group->name . html_writer::link($url, $icon); + } else { + $groups[] = $group->name; + } + } + $groups = implode(', ', $groups); + if ($managegroups and (count($usergroups) < count($allgroups))) { + $icon = html_writer::empty_tag('img', array('alt'=>get_string('addgroup', 'group'), 'src'=>$OUTPUT->pix_url('t/add'))); + $url = new moodle_url($PAGE->url, array('action'=>'addmember', 'user'=>$user->id)); + $groups .= '
'.html_writer::link($url, $icon).'
'; + } + + + // get list of enrol instances + $now = time(); + $edits = array(); + $params['userid'] = $user->id; + $ues = $DB->get_records_select('user_enrolments', "enrolid $instancessql AND userid = :userid", $params); + foreach ($ues as $ue) { + $instance = $instances[$ue->enrolid]; + $plugin = $plugins[$instance->enrol]; + + $edit = $inames[$instance->id]; + + $dimmed = false; + if ($ue->timestart and $ue->timeend) { + $edit .= ' ('.get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend))).')'; + $dimmed = ($now < $ue->timestart and $now > $ue->timeend); + } else if ($ue->timestart) { + $edit .= ' ('.get_string('periodstart', 'enrol', userdate($ue->timestart)).')'; + $dimmed = ($now < $ue->timestart); + } else if ($ue->timeend) { + $edit .= ' ('.get_string('periodend', 'enrol', userdate($ue->timeend)).')'; + $dimmed = ($now > $ue->timeend); + } + + if ($dimmed or $ue->status != ENROL_USER_ACTIVE) { + $edit = html_writer::tag('span', $edit, array('class'=>'dimmed_text')); + } + + if ($plugin->allow_unenrol($instance) and has_capability("enrol/$instance->enrol:unenrol", $context)) { + $icon = html_writer::empty_tag('img', array('alt'=>get_string('unenrol', 'enrol'), 'src'=>$OUTPUT->pix_url('t/delete'))); + $url = new moodle_url($PAGE->url, array('action'=>'unenrol', 'ue'=>$ue->id)); + $edit .= html_writer::link($url, $icon); + } + + if ($plugin->allow_manage($instance) and has_capability("enrol/$instance->enrol:manage", $context)) { + $icon = html_writer::empty_tag('img', array('alt'=>get_string('edit'), 'src'=>$OUTPUT->pix_url('t/edit'))); + $url = new moodle_url($PAGE->url, array('action'=>'edit', 'ue'=>$ue->id)); + $edit .= html_writer::link($url, $icon); + } + + $edits[] = $edit; + } + $edits = implode('
', $edits); + + $table->data[] = array("$picture wwwroot/user/view.php?id=$user->id&course=$course->id\">$fullname", $user->email, $strlastaccess, $roles, $groups, $edits); +} + +$ifilters = new single_select($PAGE->url, 'ifilter', array(0=>get_string('all')) + $inames, $ifilter, array()); +$ifilters->set_label(get_string('enrolmentinstances', 'enrol')); + +echo $OUTPUT->render($ifilters); +echo $OUTPUT->render($pagingbar); +echo html_writer::table($table); +echo $OUTPUT->render($pagingbar); + +// print enrol link or selection +$links = array(); +foreach($instances as $instance) { + $plugin = $plugins[$instance->enrol]; + if ($link = $plugin->get_manual_enrol_link($instance)) { + $links[$instance->id] = $link; + } +} +if (count($links) == 1) { + $link = reset($links); + echo $OUTPUT->single_button($link, get_string('enrolusers', 'enrol_manual'), 'get'); + +} else if (count($links) > 1) { + $options = array(); + foreach ($links as $i=>$link) { + $options[$link->out(false)] = $inames[$i]; + } + echo $OUTPUT->url_select($options, '', array(''=>get_string('enrolusers', 'enrol_manual').'...')); +} + +echo $OUTPUT->footer(); + + diff --git a/enrol/users_forms.php b/enrol/users_forms.php new file mode 100644 index 00000000000..98d82444ce8 --- /dev/null +++ b/enrol/users_forms.php @@ -0,0 +1,203 @@ +. + +/** + * Various enrol UI forms + * + * @package core + * @subpackage enrol + * @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_users_assign_form extends moodleform { + function definition() { + global $CFG, $DB, $PAGE; + + $mform = $this->_form; + + $user = $this->_customdata['user']; + $course = $this->_customdata['course']; + $context = get_context_instance(CONTEXT_COURSE, $course->id); + $assignable = $this->_customdata['assignable']; + $assignable = array_reverse($assignable, true); // students first + + $ras = get_user_roles($context, $user->id, true); + foreach ($ras as $ra) { + unset($assignable[$ra->roleid]); + } + + $mform->addElement('header','general', fullname($user)); + + $mform->addElement('select', 'roleid', get_string('addrole', 'role'), $assignable); + + $mform->addElement('hidden', 'id'); + $mform->setType('id', PARAM_INT); + + $mform->addElement('hidden', 'user'); + $mform->setType('user', PARAM_INT); + + $mform->addElement('hidden', 'action'); + $mform->setType('action', PARAM_ACTION); + + $mform->addElement('hidden', 'ifilter'); + $mform->setType('ifilter', PARAM_ALPHA); + + $mform->addElement('hidden', 'page'); + $mform->setType('page', PARAM_INT); + + $mform->addElement('hidden', 'perpage'); + $mform->setType('perpage', PARAM_INT); + + $mform->addElement('hidden', 'sort'); + $mform->setType('sort', PARAM_ALPHA); + + $mform->addElement('hidden', 'dir'); + $mform->setType('dir', PARAM_ALPHA); + + $this->add_action_buttons(); + + $this->set_data($PAGE->url->params()); + $this->set_data(array('action'=>'assign', 'user'=>$user->id)); + } +} + +class enrol_users_addmember_form extends moodleform { + function definition() { + global $CFG, $DB, $PAGE; + + $mform = $this->_form; + + $user = $this->_customdata['user']; + $course = $this->_customdata['course']; + $context = get_context_instance(CONTEXT_COURSE, $course->id); + $allgroups = $this->_customdata['allgroups']; + $usergroups = groups_get_all_groups($course->id, $user->id, 0, 'g.id'); + + $options = array(); + foreach ($allgroups as $group) { + if (isset($usergroups[$group->id])) { + continue; + } + $options[$group->id] = $group->name; + } + + $mform->addElement('header','general', fullname($user)); + + $mform->addElement('select', 'groupid', get_string('addgroup', 'group'), $options); + + $mform->addElement('hidden', 'id'); + $mform->setType('id', PARAM_INT); + + $mform->addElement('hidden', 'user'); + $mform->setType('user', PARAM_INT); + + $mform->addElement('hidden', 'action'); + $mform->setType('action', PARAM_ACTION); + + $mform->addElement('hidden', 'ifilter'); + $mform->setType('ifilter', PARAM_ALPHA); + + $mform->addElement('hidden', 'page'); + $mform->setType('page', PARAM_INT); + + $mform->addElement('hidden', 'perpage'); + $mform->setType('perpage', PARAM_INT); + + $mform->addElement('hidden', 'sort'); + $mform->setType('sort', PARAM_ALPHA); + + $mform->addElement('hidden', 'dir'); + $mform->setType('dir', PARAM_ALPHA); + + $this->add_action_buttons(); + + $this->set_data($PAGE->url->params()); + $this->set_data(array('action'=>'addmember', 'user'=>$user->id)); + } +} + +class enrol_users_edit_form extends moodleform { + function definition() { + global $CFG, $DB, $PAGE; + + $mform = $this->_form; + + $user = $this->_customdata['user']; + $course = $this->_customdata['course']; + $ue = $this->_customdata['ue']; + + + $mform->addElement('header','general', ''); + + $options = array(ENROL_USER_ACTIVE => get_string('participationactive', 'enrol'), + ENROL_USER_SUSPENDED => get_string('participationsuspended', 'enrol')); + if (isset($options[$ue->status])) { + $mform->addElement('select', 'status', get_string('participationstatus', 'enrol'), $options); + } + + $mform->addElement('date_selector', 'timestart', get_string('enroltimestart', 'enrol'), array('optional' => true)); + + $mform->addElement('date_selector', 'timeend', get_string('enroltimeend', 'enrol'), array('optional' => true)); + + $mform->addElement('hidden', 'id'); + $mform->setType('id', PARAM_INT); + + $mform->addElement('hidden', 'ue'); + $mform->setType('ue', PARAM_INT); + + $mform->addElement('hidden', 'action'); + $mform->setType('action', PARAM_ACTION); + + $mform->addElement('hidden', 'ifilter'); + $mform->setType('ifilter', PARAM_ALPHA); + + $mform->addElement('hidden', 'page'); + $mform->setType('page', PARAM_INT); + + $mform->addElement('hidden', 'perpage'); + $mform->setType('perpage', PARAM_INT); + + $mform->addElement('hidden', 'sort'); + $mform->setType('sort', PARAM_ALPHA); + + $mform->addElement('hidden', 'dir'); + $mform->setType('dir', PARAM_ALPHA); + + $this->add_action_buttons(); + + $this->set_data($PAGE->url->params()); + $this->set_data(array('action'=>'edit', 'ue'=>$ue->id, 'status'=>$ue->status, 'timestart'=>$ue->timestart, 'timeend'=>$ue->timeend)); + } + + function validation($data, $files) { + $errors = parent::validation($data, $files); + + if (!empty($data['timestart']) and !empty($data['timeend'])) { + if ($data['timestart'] >= $data['timeend']) { + $errors['timestart'] = get_string('error'); + $errors['timeend'] = get_string('error'); + } + } + + return $errors; + } +} diff --git a/grade/querylib.php b/grade/querylib.php index 2b2dd6e088c..298b3d66a28 100644 --- a/grade/querylib.php +++ b/grade/querylib.php @@ -128,7 +128,7 @@ function grade_get_course_grade($userid, $courseid_or_ids=null) { if (!is_array($courseid_or_ids)) { if (empty($courseid_or_ids)) { - if (!$courses = get_my_courses($userid, $sort='visible DESC,sortorder ASC', 'id')) { + if (!$courses = enrol_get_users_courses($userid)) { return false; } $courseids = array_keys($courses); diff --git a/grade/report/overview/lib.php b/grade/report/overview/lib.php index d05b2f0aaeb..b886d12732c 100644 --- a/grade/report/overview/lib.php +++ b/grade/report/overview/lib.php @@ -111,8 +111,8 @@ class grade_report_overview extends grade_report { public function fill_table() { global $CFG, $DB, $OUTPUT; - // MDL-11679, only show 'mycourses' instead of all courses - if ($courses = get_my_courses($this->user->id, 'c.sortorder ASC', 'id, shortname, showgrades')) { + // MDL-11679, only show user's courses instead of all courses + if ($courses = enrol_get_users_courses($this->user->id, false, 'id, shortname, showgrades')) { $numusers = $this->get_numusers(false); foreach ($courses as $course) { diff --git a/group/assign.php b/group/assign.php index 8cf1249c2f7..fcc07d3b361 100644 --- a/group/assign.php +++ b/group/assign.php @@ -86,9 +86,9 @@ if ($currentmembers) { } // Get course managers so they can be hilited in the list - if ($managerroles = get_config('', 'coursemanager')) { - $coursemanagerroles = split(',', $managerroles); - foreach ($coursemanagerroles as $roleid) { + if ($managerroles = get_config('', 'coursecontact')) { + $coursecontactroles = split(',', $managerroles); + foreach ($coursecontactroles as $roleid) { $role = $DB->get_record('role', array('id'=>$roleid)); $managers = get_role_users($roleid, $context, true, 'u.id', 'u.id ASC'); } diff --git a/group/autogroup_form.php b/group/autogroup_form.php index 4ba42a0b71c..0a703fddcff 100644 --- a/group/autogroup_form.php +++ b/group/autogroup_form.php @@ -21,10 +21,12 @@ class autogroup_form extends moodleform { $options = array(0=>get_string('all')); $options += $this->_customdata['roles']; $mform->addElement('select', 'roleid', get_string('selectfromrole', 'group'), $options); - if (!empty($COURSE->defaultrole) and array_key_exists($COURSE->defaultrole, $options)) { - $mform->setDefault('roleid', $COURSE->defaultrole); - } else if (!empty($CFG->defaultcourseroleid) and array_key_exists($CFG->defaultcourseroleid, $options)) { - $mform->setDefault('roleid', $CFG->defaultcourseroleid); + + $student = get_archetype_roles('student'); + $student = reset($student); + + if ($student and array_key_exists($student->id, $options)) { + $mform->setDefault('roleid', $student->id); } $context = get_context_instance(CONTEXT_COURSE, $COURSE->id); diff --git a/group/group_form.php b/group/group_form.php index 3d979c66f7d..20cea027d63 100644 --- a/group/group_form.php +++ b/group/group_form.php @@ -33,7 +33,7 @@ class group_form extends moodleform { $mform->addElement('editor', 'description_editor', get_string('groupdescription', 'group'), null, $editoroptions); $mform->setType('description_editor', PARAM_RAW); - $mform->addElement('passwordunmask', 'enrolmentkey', get_string('enrolmentkey', 'group'), 'maxlength="254" size="24"', get_string('enrolmentkey')); + $mform->addElement('passwordunmask', 'enrolmentkey', get_string('enrolmentkey', 'group'), 'maxlength="254" size="24"', get_string('enrolmentkey', 'group')); $mform->setHelpButton('enrolmentkey', array('groupenrolmentkey', get_string('enrolmentkey', 'group')), true); $mform->setType('enrolmentkey', PARAM_RAW); @@ -71,7 +71,7 @@ class group_form extends moodleform { } } - if (!empty($CFG->enrol_manual_usepasswordpolicy) and $data['enrolmentkey'] != '' and $group->enrolmentkey !== $data['enrolmentkey']) { + if (!empty($CFG->groupenrolmentkeypolicy) and $data['enrolmentkey'] != '' and $group->enrolmentkey !== $data['enrolmentkey']) { // enforce password policy only if changing password $errmsg = ''; if (!check_password_policy($data['enrolmentkey'], $errmsg)) { diff --git a/group/index.php b/group/index.php index 91a5b4a6636..28dd58c9d29 100644 --- a/group/index.php +++ b/group/index.php @@ -11,9 +11,6 @@ require_once('../config.php'); require_once('lib.php'); -$PAGE->requires->yui2_lib('connection'); -$PAGE->requires->js('/group/clientlib.js'); - $courseid = required_param('id', PARAM_INT); $groupid = optional_param('group', false, PARAM_INT); $userid = optional_param('user', false, PARAM_INT); @@ -45,6 +42,9 @@ $PAGE->set_url($url); // Make sure that the user has permissions to manage groups. require_login($course); +$PAGE->requires->yui2_lib('connection'); +$PAGE->requires->js('/group/clientlib.js'); + $context = get_context_instance(CONTEXT_COURSE, $course->id); if (!has_capability('moodle/course:managegroups', $context)) { redirect('/course/view.php', array('id'=>$course->id)); // Not allowed to manage all groups diff --git a/group/lib.php b/group/lib.php index 7764c44c57c..9f6c66720ea 100644 --- a/group/lib.php +++ b/group/lib.php @@ -481,31 +481,13 @@ function groups_delete_groupings($courseid, $showfeedback=false) { /** * Obtains a list of the possible roles that group members might come from, - * on a course. Generally this includes all the roles who would have - * course:view on that course, except the doanything roles. + * on a course. Generally this includes only profile roles. * @param object $context Context of course * @return Array of role ID integers, or false if error/none. */ function groups_get_possible_roles($context) { - $capability = 'moodle/course:participate'; - - // find all possible "student" roles - if ($possibleroles = get_roles_with_capability($capability, CAP_ALLOW, $context)) { - $validroleids = array(); - foreach ($possibleroles as $possiblerole) { - if ($caps = role_context_capabilities($possiblerole->id, $context, $capability)) { // resolved list - if (isset($caps[$capability]) && $caps[$capability] > 0) { // resolved capability > 0 - $validroleids[] = $possiblerole->id; - } - } - } - if (empty($validroleids)) { - return false; - } - return $validroleids; - } else { - return false; // No need to continue, since no roles have this capability set - } + $roles = get_profile_roles($context); + return array_keys($roles); } diff --git a/index.php b/index.php index 1c60a4f39d0..0220c99bad5 100644 --- a/index.php +++ b/index.php @@ -77,7 +77,7 @@ if (get_config('local_hub', 'hubenabled') && file_exists($CFG->dirroot.'/local/hub/lib.php')) { require_once($CFG->dirroot.'/local/hub/lib.php'); $hub = new local_hub(); - $hub->display_homepage(); + $hub->display_homepage(); exit; } diff --git a/lang/en/admin.php b/lang/en/admin.php index 1791e306d3b..d4fdf850481 100755 --- a/lang/en/admin.php +++ b/lang/en/admin.php @@ -45,7 +45,6 @@ $string['allowuserblockhiding'] = 'Allow users to hide blocks'; $string['allowusermailcharset'] = 'Allow user to select character set'; $string['allowuserswitchrolestheycantassign'] = 'Allow users without the assign roles capability to switch roles'; $string['allowuserthemes'] = 'Allow user themes'; -$string['allowvisiblecoursesinhiddencategories'] = 'Allow visible courses in hidden categories'; $string['antivirus'] = 'Anti-Virus'; $string['appearance'] = 'Appearance'; $string['aspellpath'] = 'Path to aspell'; @@ -121,7 +120,6 @@ $string['configallowoverride'] = 'You can allow people with the roles on the lef $string['configallowoverride2'] = 'Select which role(s) can be overridden by each role in the left column.
Note that these settings only apply to users who have either the capability moodle/role:override or the capability moodle/role:safeoverride allowed.'; $string['configallowswitch'] = 'Select which roles a user may switch to, based on which roles they already have. In addition to an entry in this table, a user must also have the moodle/role:switchroles capability to be able to switch.
Note that it is only possible to switch to roles that have the moodle/course:view capability, and that do not have the moodle/site:doanything capability, so some columns in this table are disabled.'; $string['configallowthemechangeonurl'] = 'If enabled, the theme can be changed by adding theme={themename} to any Moodle URL.'; -$string['configallowunenroll'] = 'If this is set \'Yes\', then students are allowed to unenrol themselves from courses whenever they like. Otherwise they are not allowed, and this process will be solely controlled by the teachers and administrators.'; $string['configallowuserblockhiding'] = 'Do you want to allow users to hide/show side blocks throughout this site? This feature uses Javascript and cookies to remember the state of each collapsible block, and only affects the user\'s own view.'; $string['configallowusermailcharset'] = 'Enabling this, every user in the site will be able to specify his own charset for email.'; $string['configallowuserswitchrolestheycantassign'] = 'By default, moodle/role:assign is required for users to switch roles. Enabling this setting removes this requirement, and results in the roles available in the "Switch role to" dropdown menu being determined by settings in the "Allow role assignments" table only. @@ -142,7 +140,6 @@ $string['configconvertformat'] = 'If latex, dvips and convertwwwroot address does not start with https:// this setting is turned off automatically.'; $string['configcountry'] = 'If you set a country here, then this country will be selected by default on new user accounts. To force users to choose a country, just leave this unset.'; -$string['configcoursemanager'] = 'This setting allows you to control who appears on the course description. Users need to have at least one of these roles in a course to be shown on the course description for that course.'; $string['configcourserequestnotify'] = 'Type username of user to be notified when new course requested.'; $string['configcourserequestnotify2'] = 'Users who will be notified when a course is requested. Only users who can approve course requests are listed here.'; $string['configcoursesperpage'] = 'Enter the number of courses to be display per page in a course listing.'; @@ -172,7 +169,6 @@ $string['configdebugsmtp'] = 'Enable verbose debug information during sending of $string['configdebugstringids'] = 'This option is designed to help translators. It shows the language file and string id beside each string that is output. (Changing this setting will only take effect on the next page load.)'; $string['configdebugvalidators'] = 'Enable if you want to have links to external validator servers in page footer. You may need to create new user with username w3cvalidator, and enable guest access. These changes may allow unauthorized access to server, do not enable on production sites!'; $string['configdefaultallowedmodules'] = 'For the courses which fall into the above category, which modules do you want to allow by default when the course is created?'; -$string['configdefaultcourseroleid'] = 'Users who enrol in a course will be automatically assigned this role.'; $string['configdefaulthomepage'] = 'This determines the home page for logged in users'; $string['configdefaultrequestcategory'] = 'Courses requested by users will be automatically placed in this category.'; $string['configdefaultrequestedcategory'] = 'Default category to put courses that were requested into, if they\'re approved.'; @@ -205,7 +201,6 @@ $string['configenablestats'] = 'If you choose \'yes\' here, Moodle\'s cronjob wi $string['configenabletrusttext'] = 'By default Moodle will always thoroughly clean text that comes from users to remove any possible bad scripts, media etc that could be a security risk. The Trusted Content system is a way of giving particular users that you trust the ability to include these advanced features in their content without interference. To enable this system, you need to first enable this setting, and then grant the Trusted Content permission to a specific Moodle role. Texts created or uploaded by such users will be marked as trusted and will not be cleaned before display.'; $string['configenablewebservices'] = 'Web services enable other systems to log in to this Moodle and perform operations. For extra security this feature should be disabled unless you are really using it.'; $string['configenablewsdocumentation'] = 'Enable auto-generation of web services documentation. A web service user can access to his own {$a} without login into Moodle. It display the documentation for the enabled protocols only.'; -$string['configenrolmentplugins'] = 'Please choose the enrolment plugins you wish to use. Don\'t forget to configure the settings properly.

You have to indicate which plugins are enabled, and one plugin can be set as the default plugin for interactive enrolment. To disable interactive enrolment, set "enrollable" to "No" in required courses.'; $string['configerrorlevel'] = 'Choose the amount of PHP warnings that you want to be displayed. Normal is usually the best choice.'; $string['configexcludeoldflashclients'] = 'Some versions of the Adobe Flash plugin are known to be vulnerable to attacks from malicious Flash content. You can specify a minimum supported version here, and Moodle will not show Flash files to users with lower versions. Instead they will see an alternate Flash file telling them how to upgrade. Leave this empty to disable all checks.'; $string['configexperimentalsplitrestore'] = 'If enabled, course backup files will be checked for XML errors and split into smaller parts for use in the restore process. This will result in improvements to restore robustness and execution times, particularly for medium to large course backups.'; @@ -271,7 +266,6 @@ $string['confignavcourselimit'] = 'Limits the number of courses shown to the use $string['confignavshowallcourses'] = 'Setting this ensures that all courses on the site are shown in the navigation at all times.'; $string['confignavshowcategories'] = 'Show course categories in the navigation bar and navigation blocks. This does not occur with courses the user is currently enrolled in, they will still be listed under mycourses without categories.'; $string['confignodefaultuserrolelists'] = 'This setting prevents all users from being returned from the database from deprecated calls of get_course_user, etc., for the site course if the default role provides that access. Check this, if you suffer a performance hit.'; -$string['confignonmetacoursesyncroleids'] = 'By default all role assignments from child courses are synchronised to metacourses. Roles that are selected here will not be included in the synchronisation process.'; $string['confignoreplyaddress'] = 'Emails are sometimes sent out on behalf of a user (eg forum posts). The email address you specify here will be used as the "From" address in those cases when the recipients should not be able to reply directly to the user (eg when a user chooses to keep their address private).'; $string['confignotifyloginfailures'] = 'If login failures have been recorded, email notifications can be sent out. Who should see these notifications?'; $string['confignotifyloginthreshold'] = 'If notifications about failed logins are active, how many failed login attempts by one user or one IP address is it worth notifying about?'; @@ -317,7 +311,6 @@ $string['configsectionsecurity'] = 'Security'; $string['configsectionstats'] = 'Statistics'; $string['configsectionuser'] = 'User'; $string['configsecureforms'] = 'Moodle can use an additional level of security when accepting data from web forms. If this is enabled, then the browser\'s HTTP_REFERER variable is checked against the current form address. In a very few cases this can cause problems if the user is using a firewall (eg Zonealarm) configured to strip HTTP_REFERER from their web traffic. Symptoms are getting \'stuck\' on a form. If your users are having problems with the login page (for example) you might want to disable this setting, although it might leave your site more open to brute-force password attacks. If in doubt, leave this set to \'Yes\'.'; -$string['configsendcoursewelcomemessage'] = 'If enabled, users receive a welcome message via email when they self-enrol in a course.'; $string['configsessioncookie'] = 'This setting customises the name of the cookie used for Moodle sessions. This is optional, and only useful to avoid cookies being confused when there is more than one copy of Moodle running within the same web site.'; $string['configsessioncookiedomain'] = 'This allows you to change the domain that the Moodle cookies are available from. This is useful for Moodle customisations (e.g. authentication or enrolment plugins) that need to share Moodle session information with a web application on another subdomain. WARNING: it is strongly recommended to leave this setting at the default (empty) - an incorrect value will prevent all logins to the site.'; $string['configsessioncookiepath'] = 'If you need to change where browsers send the Moodle cookies, you can change this setting to specify a subdirectory of your web site. Otherwise the default \'/\' should be fine.'; @@ -349,7 +342,6 @@ $string['configstripalltitletags'] = 'Uncheck this setting to allow HTML tags in $string['configsupportemail'] = 'This email address will be published to users of this site as the one to email when they need general help (for example, when new users create their own accounts). If this email is left blank then no such helpful email address is supplied.'; $string['configsupportname'] = 'This is the name of a person or other entity offering general help via the support email or web address.'; $string['configsupportpage'] = 'This web address will be published to users of this site as the one to go to when they need general help (for example, when new users create their own accounts). If this address is left blank then no link will be supplied.'; -$string['configteacherassignteachers'] = 'Should ordinary teachers be allowed to assign other teachers within courses they teach? If \'No\', then only course creators and admins can assign teachers.'; $string['configthemedesignermode'] = 'Normally all theme images and style sheets are cached in browsers and on the server for a very long time, for performance. If you are designing themes or developing code then you probably want to turn this mode on so that you are not served cached versions. Warning: this will make your site slower for all users! Alternatively, you can also reset the theme caches manually from the Theme selection page.'; $string['configthemelist'] = 'Leave this blank to allow any valid theme to be used. If you want to shorten the theme menu, you can specify a comma-separated list of names here (Don\'t use spaces!). For example: standard,orangewhite.'; @@ -373,7 +365,8 @@ $string['convertformat'] = 'convert output format'; $string['cookiehttponly'] = 'Only http cookies'; $string['cookiesecure'] = 'Secure cookies only'; $string['country'] = 'Default country'; -$string['coursemanager'] = 'Course managers'; +$string['coursecontact'] = 'Course contacts'; +$string['coursecontact_desc'] = 'This setting allows you to control who appears on the course description. Users need to have at least one of these roles in a course to be shown on the course description for that course.'; $string['coursemgmt'] = 'Add/edit courses'; $string['courseoverview'] = 'Course overview'; $string['courserequestnotify'] = 'Course request notification'; @@ -425,7 +418,6 @@ $string['debugsmtp'] = 'Debug email sending'; $string['debugstringids'] = 'Show origin of languages strings'; $string['debugvalidators'] = 'Show validator links'; $string['defaultallowedmodules'] = 'Default allowed modules'; -$string['defaultcourseroleid'] = 'Default role for users in a course'; $string['defaulthomepage'] = 'Default home page for users'; $string['defaulthtmleditor'] = 'Default HTML editor'; $string['defaultrequestcategory'] = 'Default category for course requests'; @@ -486,6 +478,8 @@ $string['enabletrusttext'] = 'Enable trusted content'; $string['enablewebservices'] = 'Enable web services'; $string['enablewsdocumentation'] = 'Web services documentation'; $string['encoding'] = 'Encoding'; +$string['enrolinstancedefaults'] = 'Enrolment instance defaults'; +$string['enrolinstancedefaults_desc'] = 'Default enrolment settings in new courses.'; $string['enrolmultipleusers'] = 'Enrol the users'; $string['environment'] = 'Environment'; $string['environmenterrortodo'] = 'You must solve all the environmental problems (errors) found above before proceeding to install this Moodle version!'; @@ -548,6 +542,8 @@ $string['geoipfile'] = 'GeoIP city data file'; $string['getremoteaddrconf'] = 'Logged IP address source'; $string['globalsquoteswarning'] = '

Security Warning: to operate properly, Moodle requires
that you make certain changes to your current PHP settings.

You must set register_globals=off and/or magic_quotes_gpc=on.
If possible, you should set register_globals=off to improve general
server security, setting magic_quotes_gpc=on is also recommended.

These settings are controlled by editing your php.ini, Apache/IIS
configuration or .htaccess file.

'; $string['globalswarning'] = '

SECURITY WARNING!

To operate properly, Moodle requires
that you make certain changes to your current PHP settings.

You must set register_globals=off.

This setting is controlled by editing your php.ini, Apache/IIS
configuration or .htaccess file.

'; +$string['groupenrolmentkeypolicy'] = 'Group enrolment key policy'; +$string['groupenrolmentkeypolicy_desc'] = 'Turning this on will make Moodle check group enrolment keys against a valid password policy.'; $string['googlemapkey'] = 'Google Maps API key'; $string['gotofirst'] = 'Go to first missing string'; $string['gradebook'] = 'Gradebook'; @@ -588,7 +584,7 @@ $string['includemoduleuserdata'] = 'Include module user data'; $string['incompatibleblocks'] = 'Incompatible blocks'; $string['install'] = 'Install selected language pack'; $string['installedlangs'] = 'Installed language packs'; -$string['installhijacked'] = 'Installation must be finished from the origianl IP address, sorry.'; +$string['installhijacked'] = 'Installation must be finished from the original IP address, sorry.'; $string['installsessionerror'] = 'Can not initialise PHP session, please verify that your browser accepts cookies.'; $string['intcachemax'] = 'Int. cache max'; $string['invalidlangpack'] = 'to edit this language pack, you need to put it in language folder.'; @@ -712,7 +708,6 @@ $string['nolangupdateneeded'] = 'All your language packs are up to date, no upda $string['nomissingstrings'] = 'No missing strings'; $string['nonewsettings'] = 'No new settings were added during this upgrade.'; $string['nonexistentbookmark'] = 'The bookmark you requested does not exist.'; -$string['nonmetacoursesyncroleids'] = 'Roles that are not synchronised to metacourses'; $string['noreplyaddress'] = 'No-reply address'; $string['noresults'] = 'No results found.'; $string['noroles'] = 'No roles'; @@ -864,7 +859,6 @@ $string['searchresults'] = 'Search Results'; $string['sectionerror'] = 'Section Error!'; $string['secureforms'] = 'Use additional form security'; $string['security'] = 'Security'; -$string['sendcoursewelcomemessage'] = 'Send course welcome message'; $string['server'] = 'Server'; $string['serverchecks'] = 'Server Checks'; $string['serverlimit'] = 'Server Limit'; @@ -1016,7 +1010,6 @@ $string['uubulk'] = 'Select for bulk operations'; $string['uubulkall'] = 'All users'; $string['uubulknew'] = 'New users'; $string['uubulkupdated'] = 'Updated users'; -$string['uucoursedefaultrole'] = 'Default course role'; $string['uucsvline'] = 'CSV line'; $string['uulegacy1role'] = '(Original Student) typeN=1'; $string['uulegacy2role'] = '(Original Teacher) typeN=2'; diff --git a/lang/en/enrol.php b/lang/en/enrol.php new file mode 100644 index 00000000000..8e253817e2e --- /dev/null +++ b/lang/en/enrol.php @@ -0,0 +1,63 @@ +. + +/** + * Strings for component 'core_enrol', language 'en', branch 'MOODLE_20_STABLE' + * + * @package core + * @subpackage enrol + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['actenrolshhdr'] = 'Active course enrolment plugins'; +$string['addinstance'] = 'Add method'; +$string['configenrolplugins'] = 'Please select all required plugins and arrange then in appropriate order.'; +$string['defaultenrol'] = 'Add instance to new courses'; +$string['defaultenrol_desc'] = 'It is possible to add this plugin to all new courses by default.'; +$string['deleteinstanceconfirm'] = 'Do you really want to delete enrol plugin instance "{$a->name}" with {$a->users} enrolled users?'; +$string['enrolcandidates'] = 'Not enrolled users'; +$string['enrolcandidatesmatching'] = 'Matching not enrolled users'; +$string['enrolledusers'] = 'Enrolled users'; +$string['enrolledusersmatching'] = 'Matching enrolled users'; +$string['enrolme'] = 'Enrol me in this course'; +$string['enrolmentinstances'] = 'Enrolment methods'; +$string['enrolmentnew'] = 'New enrolment in {$a}'; +$string['enrolmentnewuser'] = '{$a->user} has enrolled in course "{$a->course}"'; +$string['enrolments'] = 'Enrolments'; +$string['enrolperiod'] = 'Enrolment duration'; +$string['enrolusage'] = 'Instances / enrolments'; +$string['enroltimeend'] = 'Enrolment ends'; +$string['enroltimestart'] = 'Enrolment starts'; +$string['manageenrols'] = 'Manage enrol plugins'; +$string['manageinstance'] = 'Manage'; +$string['noexistingparticipants'] = 'No existing participants'; +$string['noguestaccess'] = 'Guests can not access this course, please try to log in.'; +$string['notenrollable'] = 'This course is not enrollable at the moment.'; +$string['notenrolledusers'] = 'Other users'; +$string['participationactive'] = 'Active'; +$string['participationstatus'] = 'Status'; +$string['participationsuspended'] = 'Suspended'; +$string['periodend'] = 'until {$a}'; +$string['periodstart'] = 'from {$a}'; +$string['periodstartend'] = 'from {$a->start} until {$a->end}'; +$string['unenrol'] = 'Unenrol'; +$string['unenrolconfirm'] = 'Do you really want to unenrol user "{$a->user}" from course "{$a->course}"?'; +$string['unenrolme'] = 'Unenrol me from {$a}'; +$string['unenrolroleusers'] = 'Unenrol users'; +$string['uninstallconfirm'] = 'You are about to completely delete the enrol plugin \'{$a}\'. This will completely delete everything in the database associated with this enrolment type. Are you SURE you want to continue?'; +$string['uninstalldeletefiles'] = 'All data associated with the enrol plugin \'{$a->plugin}\' has been deleted from the database. To complete the deletion (and prevent the plugin re-installing itself), you should now delete this directory from your server: {$a->directory}'; diff --git a/lang/en/error.php b/lang/en/error.php index 529e6f5e48a..a24832e19f8 100755 --- a/lang/en/error.php +++ b/lang/en/error.php @@ -25,7 +25,6 @@ $string['adminprimarynoedit'] = 'The primary admin cannot be edited by others'; $string['authnotexisting'] = 'The autorization plugin doesn\'t exist'; -$string['authorizeerror'] = 'Authorize error'; $string['backupcontainexternal'] = 'This backup file contains external Moodle Network Hosts that are not configured locally'; $string['backuptablefail'] = 'Backup tables could NOT be set up successfully!'; $string['blockcannotconfig'] = 'This block does not support global configuration'; @@ -104,7 +103,6 @@ $string['cannotmailconfirm'] = 'Error sending password change confirmation email $string['cannotmanualctrack'] = 'Activity does not provide manual completion tracking'; $string['cannotmapfield'] = 'Mapping collision detected - two fields maps to the same grade item {$a}'; $string['cannotmarktopic'] = 'Could not mark that topic for this course'; -$string['cannotmetacourse'] = 'Cannot not add the selected course to this meta course!'; $string['cannotmigratedatacomments'] = 'Cannot migrate data module comments'; $string['cannotmodulename'] = 'Cannot get the module name in build navigation'; $string['cannotmoduletype'] = 'Cannot get the module type in build navigation'; @@ -160,8 +158,6 @@ $string['cannotusepage'] = 'Only teachers and administrators can use this page'; $string['cannotusepage2'] = 'Sorry, you may not use this page'; $string['cannotviewprofile'] = 'You cannot view the profile of this user'; $string['cannotwritefile'] = 'Cannot write to file ({$a})'; -$string['cantunenrollfrommetacourse'] = 'You cannot unenrol from this meta course'; -$string['cantunenrollinthisrole'] = 'You cannot unenrol from this course while you are in your current role'; $string['commentmisconf'] = 'Comment ID is misconfigured'; $string['componentisuptodate'] = 'Component is up-to-date'; $string['confirmsesskeybad'] = 'Sorry, but your session key could not be confirmed to carry out this action. This security feature prevents against accidental or malicious execution of important functions in your name. Please make sure you really wanted to execute this function.'; @@ -220,7 +216,6 @@ $string['errorreadingfile'] = 'Error reading file "{$a}"'; $string['errorsavingrequest'] = 'An error occurred when trying to save your request.'; $string['errorsettinguserpref'] = 'Error setting user preference'; $string['errorunzippingfiles'] = 'Error unzipping files'; -$string['errorupdatingcoursevisibility'] = 'Error updating the course visibility'; $string['expiredkey'] = 'Expired key'; $string['failtoloadblocks'] = 'One or more blocks are registered in the database, but they all failed to load!'; $string['fieldrequired'] = '"{$a}" is a required field'; @@ -270,7 +265,6 @@ $string['invalidcoursemodule'] = 'Invalid course module ID'; $string['invalidcoursenameshort'] = 'Invalid short course name'; $string['invaliddata'] = 'Data submitted is invalid'; $string['invalidelementid'] = 'Incorrect element id!'; -$string['invalidenrol'] = 'Illegal enrolment attempted'; $string['invalidentry'] = 'This is not valid entry!'; $string['invalidevent'] = 'Invalid event'; $string['invalidfieldname'] = '"{$a}" is not a valid field name'; @@ -409,6 +403,7 @@ $string['refoundtoorigi'] = 'Refunded to original amount: {$a}'; $string['remotedownloaderror'] = 'Download of component to your server failed, please verify proxy settings, PHP cURL extension is highly recommended.

You must download the {$a->url} file manually, copy it to "{$a->dest}" in your server and unzip it there.'; $string['remotedownloadnotallowed'] = 'Download of components to your server isn\'t allowed (allow_url_fopen is disabled).

You must download the {$a->url} file manually, copy it to "{$a->dest}" in your server and unzip it there.'; $string['reportnotavailable'] = 'This type of report is only available for the site course'; +$string['requireloginerror'] = 'Cource or activity not accessible.'; $string['restorechecksumfailed'] = 'Some problem happened with the restore information stored in your session. Please check your PHP memory/DB package size limits. Restore stopped.'; $string['restrictedcontextexception'] = 'Sorry, execution of external function violates context restriction.'; $string['restricteduser'] = 'Sorry, but your current account "{$a}" is restricted from doing that'; diff --git a/lang/en/group.php b/lang/en/group.php index 152423cb13f..166a116db53 100644 --- a/lang/en/group.php +++ b/lang/en/group.php @@ -24,6 +24,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['addgroup'] = 'Add user into group'; $string['addgroupstogrouping'] = 'Add group to grouping'; $string['addgroupstogroupings'] = 'Add/remove groups'; $string['adduserstogroup'] = 'Add/remove users'; @@ -138,6 +139,8 @@ $string['potentialmembs'] = 'Potential members'; $string['printerfriendly'] = 'Printer-friendly display'; $string['random'] = 'Randomly'; $string['removegroupfromselectedgrouping'] = 'Remove group from grouping'; +$string['removefromgroup'] = 'Remove user from group {$a}'; +$string['removefromgroupconfirm'] = 'Do you really want to remove user "{$a->user}" from group "{$a->group}"?'; $string['removegroupingsmembers'] = 'Remove all groups from groupings'; $string['removegroupsmembers'] = 'Remove all group members'; $string['removeselectedusers'] = 'Remove selected users'; diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 9cc91dec976..12c7f092b8c 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -72,7 +72,6 @@ $string['adminhelpassignadmins'] = 'Admins can do anything and go anywhere in th $string['adminhelpassigncreators'] = 'Course creators can create new courses'; $string['adminhelpassignsiteroles'] = 'Apply defined site roles to specific users'; $string['adminhelpassignstudents'] = 'Go into a course and add students from the admin menu'; -$string['adminhelpassignteachers'] = 'Find a course then use the icon to add teachers'; $string['adminhelpauthentication'] = 'You can use internal user accounts or external databases'; $string['adminhelpbackup'] = 'Configure automated backups and their schedule'; $string['adminhelpconfiguration'] = 'Configure how the site looks and works'; @@ -80,7 +79,6 @@ $string['adminhelpconfigvariables'] = 'Configure variables that affect general o $string['adminhelpcourses'] = 'Define courses and categories and assign people to them, edit pending courses'; $string['adminhelpeditorsettings'] = 'Define basic settings for HTML editor'; $string['adminhelpedituser'] = 'Browse the list of user accounts and edit any of them'; -$string['adminhelpenrolments'] = 'Choose internal or external ways to control enrolments'; $string['adminhelpenvironment'] = 'Check how your server suits current and future installation requirements'; $string['adminhelpfailurelogs'] = 'Browse logs of failed logins'; $string['adminhelphealthcenter'] = 'Automatic detection of site problems'; @@ -147,10 +145,6 @@ $string['assessment'] = 'Assessment'; $string['assignadmins'] = 'Assign admins'; $string['assigncreators'] = 'Assign creators'; $string['assignsiteroles'] = 'Assign site-wide roles'; -$string['assignstudents'] = 'Enrol students'; -$string['assignstudentsnote'] = 'Note: it may not be necessary to use this page, since it is possible for students to enrol themselves in this course.'; -$string['assignstudentspass'] = 'All you may need to do is notify your students of the enrolment key for this course, which is currently set to: \'{$a}\''; -$string['assignteachers'] = 'Assign teachers'; $string['authenticateduser'] = 'Authenticated user'; $string['authenticateduserdescription'] = 'All logged in users.'; $string['authentication'] = 'Authentication'; @@ -187,7 +181,6 @@ $string['backupkeephelp'] = 'How many recent backups for each course do you want $string['backuplogdetailed'] = 'Detailed execution log'; $string['backuploglaststatus'] = 'Last execution log'; $string['backuplogshelp'] = 'If enabled, then course logs will be included in automated backups'; -$string['backupmetacoursehelp'] = 'If enabled, then metacourse info (inherited enrolments) will be included in automated backups'; $string['backupmissinguserinfoperms'] = 'Note: This backup contains no user data. Exercise and Workshop activities will not be included in the backup, since these modules are not compatible with this type of backup.'; $string['backupnext'] = 'Next backup'; $string['backupnoneusersinfo'] = 'Note: This backup contains no users and so all activities have been switched to "without user data" mode. Exercise and Workshop activities will not be included in the backup, since these modules are not compatible with this type of backup.'; @@ -301,27 +294,16 @@ $string['coursecompletions'] = 'Course completions'; $string['coursecreators'] = 'Course creator'; $string['coursecreatorsdescription'] = 'Course creators can create new courses.'; $string['coursedeleted'] = 'Deleted course {$a}'; -$string['courseenrolend'] = 'Course enrolment end'; -$string['courseenrolenddate'] = 'Course enrolment end date'; -$string['courseenrolstart'] = 'Course enrolment start'; -$string['courseenrolstartdate'] = 'Course enrolment start'; $string['coursefiles'] = 'Course files'; $string['courseformatdata'] = 'Course format data'; $string['courseformats'] = 'Course formats'; $string['coursegrades'] = 'Course grades'; $string['coursehelpcategory'] = 'Position the course on the course listing and may make it easier for students to find it.'; -$string['coursehelpenrollable'] = 'Are students able to enrol themselves using the default interactive enrolment plugin'; -$string['coursehelpenrolmentkey'] = 'If set, users will need this key to be enrolled into the course.'; -$string['coursehelpenrolmentplugins'] = 'Default interactive enrolment plugin.'; -$string['coursehelpexpirynotifystudents'] = 'If an enrolment duration has been specified, then this setting determines whether students receive email notification when they are about to be unenrolled from the course.'; -$string['coursehelpexpirythreshold'] = 'If an enrolment duration has been specified, then this setting determines the number of days notice given before students are unenrolled from the course.'; $string['coursehelpforce'] = 'Force the course group mode to every activity in the course.'; $string['coursehelpformat'] = 'The course main page will be displayed in this format.'; $string['coursehelphiddensections'] = 'How the hidden sections in the course are displayed to students.'; $string['coursehelpmaximumupload'] = 'Define the largest size of file that can be uploaded in this course, limited by the site-wide setting.'; -$string['coursehelpmetacourse'] = 'Set the course a metacourse. A meta course takes enrolments (and other role assignments) from a "child" course or courses.'; $string['coursehelpnewsitemsnumber'] = 'Number of recent items appearing on the course home page, in a news box down the right-hand side
(0 means the news box won\'t appear).'; -$string['coursehelpnotify'] = 'If an enrolment duration has been specified, then this setting determines whether teachers receive email notification when a student is about to be unenrolled from the course.'; $string['coursehelpnumberweeks'] = 'Number of weeks/topics displayed on the course main page.'; $string['coursehelpshowgrades'] = 'Enable the display of the gradebook. It does not prevent grades from being displayed within the individual activities.'; $string['coursehidden'] = 'This course is currently unavailable to students'; @@ -384,7 +366,6 @@ $string['creatinggroupingsgroups'] = 'Adding groups into groupings'; $string['creatinggroups'] = 'Creating groups'; $string['creatinglogentries'] = 'Creating log entries'; $string['creatingmessagesinfo'] = 'Creating messages info'; -$string['creatingmetacoursedata'] = 'Creating metacourse info'; $string['creatingmodroles'] = 'Creating module level role assignments and overrides'; $string['creatingnewcourse'] = 'Creating new course'; $string['creatingrolesdefinitions'] = 'Creating roles definitions'; @@ -624,39 +605,6 @@ The new password was automatically generated - you might like to $string['enable'] = 'Enable'; $string['encryptedcode'] = 'Encrypted code'; $string['english'] = 'English'; -$string['enroldate'] = 'Date range'; -$string['enroldetails'] = 'Enrolment details'; -$string['enrolenddate'] = 'End date'; -$string['enrolenddaterror'] = 'Enrolment end date cannot be earlier than start date'; -$string['enrollable'] = 'Course enrollable'; -$string['enrollable_help'] = 'This setting determines whether students are able to enrol themselves using the default interactive enrolment plugin (e.g. internal enrolment) or whether they obtain the message "This course is not enrollable at the moment." - -This setting has no effect on non-interactive enrolment plugins. Also, users can always be assigned the role of student via the assign roles link in the course administration block.'; -$string['enrolledincourse'] = 'Enrolled in course "{$a}"'; -$string['enrolledincoursenot'] = 'Not enrolled in course "{$a}"'; -$string['enrolledincoursenotrole'] = 'Error enrolling into "{$a->course}" as "{$a->role}"'; -$string['enrolledincourserole'] = 'Enrolled in "{$a->course}" as "{$a->role}"'; -$string['enrollfirst'] = 'You have to enrol in one of the courses before you can use the site activities'; -$string['enrolme'] = 'Enrol me in this course'; -$string['enrolmentconfirmation'] = 'You are about to enrol yourself as a member of this course.
Are you sure you wish to do this?'; -$string['enrolmentend'] = 'Enrolment ends'; -$string['enrolmentkey'] = 'Enrolment key'; -$string['enrolmentkeyfrom'] = 'This course requires an \'enrolment key\' - a one-time
-password that you should have received from {$a}'; -$string['enrolmentkeyfromguest'] = 'This course requires an \'enrolment key\' - as a guest
-you must enter it each time you enter the course. You should have received it from {$a}'; -$string['enrolmentkeyhint'] = 'That enrolment key was incorrect, please try again
-(Here\'s a hint - it starts with \'{$a}\')'; -$string['enrolmentnew'] = 'New enrolment in {$a}'; -$string['enrolmentnewuser'] = '{$a->user} has enrolled in course "{$a->course}"'; -$string['enrolmentnointernal'] = 'Manual enrolments are currently not enabled'; -$string['enrolmentnotyet'] = 'Sorry, you can not access this course until
{$a}'; -$string['enrolmentplugins'] = 'Enrolment plugins'; -$string['enrolmentplugins_help'] = 'This setting determines whether an interactive enrolment plugin is used. Interactive enrolment is when a user has to do something interactively in order to be enrolled, such as clicking "Yes, I do" (internal enrolment) or paying some money. If a non-interactive enrolment plugin is used, the setting may be left as site default.'; -$string['enrolments'] = 'Enrolments'; -$string['enrolmentstart'] = 'Enrolment started'; -$string['enrolperiod'] = 'Enrolment duration'; -$string['enrolstartdate'] = 'Start date'; $string['entercourse'] = 'Click to enter this course'; $string['enteremail'] = 'Enter your email address'; $string['enteremailaddress'] = 'Enter in your email address to reset your @@ -905,7 +853,6 @@ $string['childcourses'] = 'Child courses'; $string['choose'] = 'Choose'; $string['choosecourse'] = 'Choose a course'; $string['choosedots'] = 'Choose...'; -$string['chooseenrolmethod'] = 'Choose enrolment plugin'; $string['chooselivelogs'] = 'Or watch current activity'; $string['chooselogs'] = 'Choose which logs you want to see'; $string['choosereportfilter'] = 'Choose a filter for the report'; @@ -928,7 +875,6 @@ $string['importdataexported'] = 'Exported data from \'from\' course successfully $string['importdatafinished'] = 'Import complete! Continue to your course'; $string['importdatafrom'] = 'Find a course to import data from:'; $string['importgroups'] = 'Import groups'; -$string['importmetacoursenote'] = 'Use this form to add courses to your meta course (this will import the enrolments)'; $string['inactive'] = 'Inactive'; $string['include'] = 'Include'; $string['includeallusers'] = 'Include all users'; @@ -1036,10 +982,6 @@ $string['managecourses'] = 'Manage courses'; $string['managedatabase'] = 'Database'; $string['manageeditorfiles'] = 'Manage files used by editor'; $string['managefilters'] = 'Filters'; -$string['managemeta'] = 'Is this a meta course?'; -$string['managemeta_help'] = 'A meta course takes enrolments (and other role assignments) from a "child" course or courses. In other words, for every child course added to the meta course, all students (and users in other roles) are also enrolled in the meta course. Individual students cannot be added to a meta course, only child courses via the "Child courses" link in the course administration bock.'; -$string['managemetadisabled'] = 'This is disabled because this course is already in a meta course'; -$string['managemetaexplan'] = '(This means that enrolments are inherited from other courses)'; $string['managemodules'] = 'Modules'; $string['manageroles'] = 'Roles and permissions'; $string['markedthistopic'] = 'This topic is highlighted as the current topic'; @@ -1064,17 +1006,6 @@ $string['messageprovider:instantmessage'] = 'Personal messages between users'; $string['messageprovider:instantmessage_help'] = 'This section configures what happens to messages that are sent to you directly from other users on this site.'; $string['messageselect'] = 'Select this user as an email recipient'; $string['messageselectadd'] = 'Add / send message'; -$string['metaaddcourse'] = 'Add this course'; -$string['metaalreadycourses'] = 'Courses already assigned'; -$string['metaalreadyhascourses'] = 'This meta course already has child courses.'; -$string['metaalreadyhasenrolments'] = 'This course already has normal enrolments.'; -$string['metaalreadyinmeta'] = 'This course is already part of a meta course.'; -$string['metaassigncourses'] = 'Assign courses'; -$string['metacourse'] = 'Metacourse'; -$string['metanoalreadycourses'] = 'No courses already assigned'; -$string['metanopotentialcourses'] = 'No courses available'; -$string['metapotentialcourses'] = 'Courses available'; -$string['metaremovecourse'] = 'Remove this course'; $string['migratinggrades'] = 'Migrating grades'; $string['min'] = 'min'; $string['mins'] = 'mins'; @@ -1211,10 +1142,6 @@ $string['nocourses'] = 'No courses'; $string['nocoursesfound'] = 'No courses were found with the words \'{$a}\''; $string['nocoursesyet'] = 'No courses in this category'; $string['nodstpresets'] = 'The administrator has not enabled Daylight Savings Time support.'; -$string['noexistingadmins'] = 'No existing admins, this is a serious error and you should never have seen this message.'; -$string['noexistingcreators'] = 'No existing creators'; -$string['noexistingstudents'] = 'No existing students'; -$string['noexistingteachers'] = 'No existing teachers'; $string['nofilesselected'] = 'No files have been selected to restore'; $string['nofilesyet'] = 'No files have been uploaded to your course yet'; $string['nograde'] = 'No grade'; @@ -1249,7 +1176,6 @@ $string['nostudentsyet'] = 'No students enrolled in this course yet'; $string['nosuchemail'] = 'No such email address'; $string['notavailable'] = 'Not available'; $string['noteachersyet'] = 'No teachers in this course yet'; -$string['notenrollable'] = 'This course is not enrollable at the moment.'; $string['notenrolled'] = '{$a} is not enrolled in this course.'; $string['notenrolledprofile'] = 'This profile is not available because this user is not enrolled in this course.'; $string['noteusercannotrolldatesoncontext'] = 'Note: The ability to roll dates when restoring this backup has been disabled because you lack the required permissions.'; @@ -1259,8 +1185,6 @@ $string['nothingtodisplay'] = 'Nothing to display'; $string['notice'] = 'Notice'; $string['noticenewerbackup'] = 'This backup file has been created with Moodle {$a->backuprelease} ({$a->backupversion}) and it\'s newer than your currently installed Moodle {$a->serverrelease} ({$a->serverversion}). This could cause some inconsistencies because backwards compatibility of backup files cannot be guaranteed.'; $string['notifications'] = 'Notifications'; -$string['notify'] = 'Notify teachers'; -$string['notify_help'] = 'If an enrolment duration has been specified, then this setting determines whether teachers receive email notification when a student is about to be unenrolled from the course.'; $string['notifyloginfailuresmessage'] = '{$a->time}, IP: {$a->ip}, User: {$a->info}'; $string['notifyloginfailuresmessageend'] = 'You can view these logs at {$a}/course/report/log/index.php?id=1&chooselog=1&modid=site_errors.'; $string['notifyloginfailuresmessagestart'] = 'Here is a list of failed login attempts at {$a} since you were last notified'; @@ -1299,7 +1223,6 @@ $string['pageheaderconfigablock'] = 'Configuring a block in %fullname%'; $string['pageshouldredirect'] = 'This page should automatically redirect. If nothing is happening please use the continue link below.'; $string['parentcategory'] = 'Parent category'; $string['parentcoursenotfound'] = 'Parent course not found!'; -$string['parentcoursenotmetacourse'] = 'Parent course not metacourse!'; $string['parentfolder'] = 'Parent folder'; $string['participants'] = 'Participants'; $string['participantslist'] = 'Participants list'; @@ -1723,12 +1646,6 @@ $string['trysearching'] = 'Try searching instead.'; $string['turneditingoff'] = 'Turn editing off'; $string['turneditingon'] = 'Turn editing on'; $string['undecided'] = 'Undecided'; -$string['unenrol'] = 'Unenrol'; -$string['unenrolallstudents'] = 'Unenrol all students'; -$string['unenrolallstudentssure'] = 'Are you sure you want to completely unenrol all students from this course?'; -$string['unenrolme'] = 'Unenrol me from {$a}'; -$string['unenrolroleusers'] = 'Unenrol users'; -$string['unenrolsure'] = 'Are you sure you want to unenrol {$a} from this course?'; $string['unfinished'] = 'Unfinished'; $string['unknowncategory'] = 'Unknown category'; $string['unlimited'] = 'Unlimited'; @@ -1900,4 +1817,4 @@ $string['yourlastlogin'] = 'Your last login was'; $string['yourself'] = 'yourself'; $string['yourteacher'] = 'your {$a}'; $string['yourwordforx'] = 'Your word for \'{$a}\''; -$string['zippingbackup'] = 'Zipping backup'; \ No newline at end of file +$string['zippingbackup'] = 'Zipping backup'; diff --git a/lang/en/role.php b/lang/en/role.php index b7e9bb1bd31..b2b1b499e96 100644 --- a/lang/en/role.php +++ b/lang/en/role.php @@ -48,6 +48,7 @@ $string['archetypeuser'] = 'ARCHETYPE: Authenticated user'; $string['assignanotherrole'] = 'Assign another role'; $string['assignerror'] = 'Error while assigning the role {$a->role} to user {$a->user}.'; $string['assignglobalroles'] = 'Assign system roles'; +$string['assignedroles'] = 'Assigned roles'; $string['assignmentcontext'] = 'Assignment context'; $string['assignmentoptions'] = 'Assignment options'; $string['assignrolenameincontext'] = 'Assign role \'{$a->role}\' in {$a->context}'; @@ -111,14 +112,14 @@ $string['course:changefullname'] = 'Change course full name'; $string['course:changeidnumber'] = 'Change course ID number'; $string['course:changeshortname'] = 'Change course short name'; $string['course:changesummary'] = 'Change course summary'; +$string['course:enrolconfig'] = 'Configure enrol instances in courses'; +$string['course:enrolreview'] = 'Review course enrolments'; $string['course:manageactivities'] = 'Manage activities'; $string['course:managefiles'] = 'Manage files'; $string['course:managegrades'] = 'Manage grades'; $string['course:managegroups'] = 'Manage groups'; -$string['course:managemetacourse'] = 'Manage metacourse'; $string['course:managescales'] = 'Manage scales'; $string['course:markcomplete'] = 'Mark users as complete in course completion'; -$string['course:participate'] = 'Participate in courses'; $string['course:publish'] = 'Publish a course into hub'; $string['course:request'] = 'Request new courses'; $string['course:reset'] = 'Reset course'; @@ -152,7 +153,6 @@ $string['duplicaterolesure'] = 'Are you sure that you want to duplicate role "{$ $string['editingrolex'] = 'Editing role \'{$a}\''; $string['editrole'] = 'Edit role'; $string['editxrole'] = 'Edit {$a} role'; -$string['enrolmentoptions'] = 'Enrolment options'; $string['errorbadrolename'] = 'Incorrect role name'; $string['errorbadroleshortname'] = 'Incorrect role short name'; $string['errorexistsrolename'] = 'Role name already exists'; @@ -211,8 +211,6 @@ $string['manager'] = 'Manager'; $string['managerdescription'] = 'Managers can access course and modify them, they usually do not participate in courses.'; $string['manageroles'] = 'Manage roles'; $string['maybeassignedin'] = 'Context types where this role may be assigned'; -$string['metaassignerror'] = 'Can not assign this role to user "{$a}" because Manage metacourse capability is needed.'; -$string['metaunassignerror'] = 'Role of user "{$a}" was automatically reassigned, please unassign the role in child courses instead.'; $string['morethan'] = 'More than {$a}'; $string['multipleroles'] = 'Multiple roles'; $string['my:manageblocks'] = 'Manage myMoodle page blocks'; @@ -304,7 +302,6 @@ $string['roleselect'] = 'Select role'; $string['role:switchroles'] = 'Switch to other roles'; $string['roletoassign'] = 'Role to assign'; $string['roletooverride'] = 'Role to override'; -$string['role:unassignself'] = 'Unassign own roles'; $string['role:viewhiddenassigns'] = 'View hidden role assignments'; $string['safeoverridenotice'] = 'Note: Capabilities with higher risks are locked because you are only allowed to override safe capabilities.'; $string['selectanotheruser'] = 'Select another user'; @@ -338,7 +335,9 @@ $string['tag:edit'] = 'Edit existing tags'; $string['tag:editblocks'] = 'Edit blocks in tags pages'; $string['tag:manage'] = 'Manage all tags'; $string['thisusersroles'] = 'This user\'s role assignments'; +$string['unassignarole'] = 'Unassign role {$a}'; $string['unassignerror'] = 'Error while unassigning the role {$a->role} from user {$a->user}.'; +$string['unassignconfirm'] = 'Do you really want to unassign "{$a->role}" role from user "{$a->user}"?'; $string['user:changeownpassword'] = 'Change own password'; $string['user:create'] = 'Create users'; $string['user:delete'] = 'Delete users'; diff --git a/lib/accesslib.php b/lib/accesslib.php index 22a908f0dad..d47704853eb 100755 --- a/lib/accesslib.php +++ b/lib/accesslib.php @@ -168,6 +168,8 @@ define('ROLENAME_BOTH', 2); define('ROLENAME_ORIGINALANDSHORT', 3); /** rolename displays - the name as defined by a role alias, in raw form suitable for editing*/ define('ROLENAME_ALIAS_RAW', 4); +/** rolename displays - the name is simply short role name*/ +define('ROLENAME_SHORT', 5); /** size limit for context cache */ if (!defined('MAX_CONTEXT_CACHE_SIZE')) { @@ -700,19 +702,19 @@ function is_siteadmin($user_or_id = NULL) { /** * Returns true if user has at least one role assign - * of 'coursemanager' role (is potentially listed in some course descriptions). + * of 'coursecontact' role (is potentially listed in some course descriptions). * @param $userid * @return unknown_type */ -function has_coursemanager_role($userid) { +function has_coursecontact_role($userid) { global $DB; - if (empty($CFG->coursemanager)) { + if (empty($CFG->coursecontact)) { return false; } $sql = "SELECT 1 FROM {role_assignments} - WHERE userid = :userid AND roleid IN ($CFG->coursemanager)"; + WHERE userid = :userid AND roleid IN ($CFG->coursecontact)"; return $DB->record_exists($sql, array('userid'=>$userid)); } @@ -920,211 +922,26 @@ function require_capability($capability, $context, $userid = NULL, $doanything = /** * Get an array of courses where cap requested is available + * and user is enrolled, this can be relatively slow. * - * Get an array of courses (with magic extra bits) - * where the accessdata and in DB enrolments show - * that the cap requested is available. - * - * The main use is for get_my_courses(). - * - * Notes - * - * - $fields is an array of fieldnames to ADD - * so name the fields you really need, which will - * be added and uniq'd - * - * - the course records have $c->context which is a fully - * valid context object. Saves you a query per course! - * - * - the course records have $c->categorypath to make - * category lookups cheap - * - * - current implementation is split in - - * - * - if the user has the cap systemwide, stupidly - * grab *every* course for a capcheck. This eats - * a TON of bandwidth, specially on large sites - * with separate DBs... - * - * - otherwise, fetch "likely" courses with a wide net - * that should get us _cheaply_ at least the courses we need, and some - * we won't - we get courses that... - * - are in a category where user has the cap - * - or where use has a role-assignment (any kind) - * - or where the course has an override on for this cap - * - * - walk the courses recordset checking the caps on each one - * the checks are all in memory and quite fast - * (though we could implement a specialised variant of the - * has_capability_in_accessdata() code to speed it up) - * - * @global object - * @global object * @param string $capability - name of the capability - * @param array $accessdata - accessdata session array - * @param bool $doanything_ignored - admin roles are completely ignored here + * @param array $accessdata_ignored + * @param bool $doanything_ignored * @param string $sort - sorting fields - prefix each fieldname with "c." * @param array $fields - additional fields you are interested in... - * @param int $limit - set if you want to limit the number of courses + * @param int $limit_ignored * @return array $courses - ordered array of course objects - see notes above */ -function get_user_courses_bycap($userid, $cap, $accessdata, $doanything_ignored, $sort='c.sortorder ASC', $fields=NULL, $limit=0) { +function get_user_courses_bycap($userid, $cap, $accessdata_ignored, $doanything_ignored, $sort='c.sortorder ASC', $fields=NULL, $limit_ignored=0) { - global $CFG, $DB; + //TODO: this should be most probably deprecated - // Slim base fields, let callers ask for what they need... - $basefields = array('id', 'sortorder', 'shortname', 'idnumber'); - - if (!is_null($fields)) { - $fields = array_merge($basefields, $fields); - $fields = array_unique($fields); - } else { - $fields = $basefields; - } - // If any of the fields is '*', leave it alone, discarding the rest - // to avoid ambiguous columns under some silly DBs. See MDL-18746 :-D - if (in_array('*', $fields)) { - $fields = array('*'); - } - $coursefields = 'c.' .implode(',c.', $fields); - - $sort = trim($sort); - if ($sort !== '') { - $sort = "ORDER BY $sort"; - } - - $sysctx = get_context_instance(CONTEXT_SYSTEM); - if (has_capability_in_accessdata($cap, $sysctx, $accessdata)) { - // - // Apparently the user has the cap sitewide, so walk *every* course - // (the cap checks are moderately fast, but this moves massive bandwidth w the db) - // Yuck. - // - $sql = "SELECT $coursefields, - ctx.id AS ctxid, ctx.path AS ctxpath, - ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel, - cc.path AS categorypath - FROM {course} c - JOIN {course_categories} cc - ON c.category=cc.id - JOIN {context} ctx - ON (c.id=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.") - $sort "; - $rs = $DB->get_recordset_sql($sql); - } else { - // - // narrow down where we have the caps to a few contexts - // this will be a combination of - // - courses where user has an explicit enrolment - // - courses that have an override (any status) on that capability - // - categories where user has the rights (granted status) on that capability - // - $sql = "SELECT ctx.* - FROM {context} ctx - WHERE ctx.contextlevel=".CONTEXT_COURSECAT." - ORDER BY ctx.depth"; - $rs = $DB->get_recordset_sql($sql); - $catpaths = array(); - foreach ($rs as $catctx) { - if ($catctx->path != '' - && has_capability_in_accessdata($cap, $catctx, $accessdata)) { - $catpaths[] = $catctx->path; - } + $courses = enrol_get_users_courses($userid, true, $fields, $sort); + foreach ($courses as $id=>$course) { + $context = get_context_instance(CONTEXT_COURSE, $id); + if (!has_capability($cap, $context, $userid)) { + unset($courses[$id]); } - $rs->close(); - $catclause = ''; - $params = array(); - if (count($catpaths)) { - $cc = count($catpaths); - for ($n=0;$n<$cc;$n++) { - $catpaths[$n] = "ctx.path LIKE '{$catpaths[$n]}/%'"; - } - $catclause = 'WHERE (' . implode(' OR ', $catpaths) .')'; - } - unset($catpaths); - - /// UNION 3 queries: - /// - user role assignments in courses - /// - user capability (override - any status) in courses - /// - user right (granted status) in categories (optionally executed) - /// Enclosing the 3-UNION into an inline_view to avoid column names conflict and making the ORDER BY cross-db - /// and to allow selection of TEXT columns in the query (MSSQL and Oracle limitation). MDL-16209 - $sql = " - SELECT $coursefields, ctxid, ctxpath, ctxdepth, ctxlevel, ctxinstance, categorypath - FROM ( - SELECT c.id, - ctx.id AS ctxid, ctx.path AS ctxpath, - ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel, ctx.instanceid AS ctxinstance, - cc.path AS categorypath - FROM {course} c - JOIN {course_categories} cc - ON c.category=cc.id - JOIN {context} ctx - ON (c.id=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.") - JOIN {role_assignments} ra - ON (ra.contextid=ctx.id AND ra.userid=:userid) - UNION - SELECT c.id, - ctx.id AS ctxid, ctx.path AS ctxpath, - ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel, ctx.instanceid AS ctxinstance, - cc.path AS categorypath - FROM {course} c - JOIN {course_categories} cc - ON c.category=cc.id - JOIN {context} ctx - ON (c.id=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.") - JOIN {role_capabilities} rc - ON (rc.contextid=ctx.id AND (rc.capability=:cap)) "; - - if (!empty($catclause)) { /// If we have found the right in categories, add child courses here too - $sql .= " - UNION - SELECT c.id, - ctx.id AS ctxid, ctx.path AS ctxpath, - ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel, ctx.instanceid AS ctxinstance, - cc.path AS categorypath - FROM {course} c - JOIN {course_categories} cc - ON c.category=cc.id - JOIN {context} ctx - ON (c.id=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.") - $catclause"; - } - - /// Close the inline_view and join with courses table to get requested $coursefields - $sql .= " - ) inline_view - INNER JOIN {course} c - ON inline_view.id = c.id"; - - /// To keep cross-db we need to strip any prefix in the ORDER BY clause for queries using UNION - $sql .= " - " . preg_replace('/[a-z]+\./i', '', $sort); /// Add ORDER BY clause - - $params['userid'] = $userid; - $params['cap'] = $cap; - $rs = $DB->get_recordset_sql($sql, $params); - } - -/// Confirm rights (granted capability) for each course returned - $courses = array(); - $cc = 0; // keep count - if ($rs) { - foreach ($rs as $c) { - // build the context obj - context_instance_preload($c); - $context = get_context_instance(CONTEXT_COURSE, $c->id); - - if (has_capability_in_accessdata($cap, $context, $accessdata)) { - if ($limit > 0 && $cc >= $limit) { - break; - } - - $courses[] = $c; - $cc++; - } - } - $rs->close(); } return $courses; @@ -1134,7 +951,7 @@ function get_user_courses_bycap($userid, $cap, $accessdata, $doanything_ignored, /** * Return a nested array showing role assignments * all relevant role capabilities for the user at - * site/metacourse/course_category/course levels + * site/course_category/course levels * * We do _not_ delve deeper than courses because the number of * overrides at the module/block levels is HUGE. @@ -1679,15 +1496,12 @@ function reload_all_capabilities() { * * Note - assumes a course context! * - * @global object - * @global object * @param object $content * @param int $roleid * @param array $accessdata * @return array Returns access data */ -function load_temp_role($context, $roleid, $accessdata) { - +function load_temp_role($context, $roleid, array $accessdata) { global $CFG, $DB; // @@ -1738,57 +1552,21 @@ function load_temp_role($context, $roleid, $accessdata) { return $accessdata; } - /** - * Check all the login enrolment information for the given user object - * by querying the enrolment plugins - * - * @global object - * @param object $user - * @return void + * Removes any extra guest roels from accessdata + * @param object $context + * @param array $accessdata + * @return array access data */ -function check_enrolment_plugins(&$user) { - global $CFG; +function remove_temp_roles($context, array $accessdata) { + global $DB, $USER; + $sql = "SELECT DISTINCT ra.roleid AS id + FROM {role_assignments} ra + WHERE ra.contextid = :contextid AND ra.userid = :userid"; + $ras = $DB->get_records_sql($sql, array('contextid'=>$context->id, 'userid'=>$USER->id)); - if (empty($user->id) or isguestuser($user)) { - // shortcut - there is no enrolment work for guests and not-logged-in users - return; - } - - static $inprogress = array(); // To prevent this function being called more than once in an invocation - - if (!empty($inprogress[$user->id])) { - return; - } - - $inprogress[$user->id] = true; // Set the flag - - require_once($CFG->dirroot .'/enrol/enrol.class.php'); - - if (!($plugins = explode(',', $CFG->enrol_plugins_enabled))) { - $plugins = array($CFG->enrol); - } - - foreach ($plugins as $plugin) { - $enrol = enrolment_factory::factory($plugin); - if (method_exists($enrol, 'setup_enrolments')) { /// Plugin supports Roles (Moodle 1.7 and later) - $enrol->setup_enrolments($user); - } else { /// Run legacy enrolment methods - if (method_exists($enrol, 'get_student_courses')) { - $enrol->get_student_courses($user); - } - if (method_exists($enrol, 'get_teacher_courses')) { - $enrol->get_teacher_courses($user); - } - - /// deal with $user->students and $user->teachers stuff - unset($user->student); - unset($user->teacher); - } - unset($enrol); - } - - unset($inprogress[$user->id]); // Unset the flag + $accessdata['ra'][$context->path] = array_keys($ras); + return $accessdata; } /** @@ -2318,15 +2096,6 @@ function get_context_instance($contextlevel, $instance=0, $strictness=IGNORE_MIS global $DB, $ACCESSLIB_PRIVATE; static $allowed_contexts = array(CONTEXT_SYSTEM, CONTEXT_USER, CONTEXT_COURSECAT, CONTEXT_COURSE, CONTEXT_MODULE, CONTEXT_BLOCK); - if ($contextlevel === 'clearcache') { - // TODO: Remove for v2.0 - // No longer needed, but we'll catch it to avoid erroring out on custom code. - // This used to be a fix for MDL-9016 - // "Restoring into existing course, deleting first - // deletes context and doesn't recreate it" - return false; - } - /// System context has special cache if ($contextlevel == CONTEXT_SYSTEM) { return get_system_context(); @@ -2535,7 +2304,7 @@ function delete_role($roleid) { global $CFG, $DB; // first unssign all users - role_unassign($roleid); + role_unassign_all(array('roleid'=>$roleid)); // cleanup all references to this role, ignore errors $DB->delete_records('role_capabilities', array('roleid'=>$roleid)); @@ -2671,259 +2440,212 @@ function get_roles_with_capability($capability, $permission=NULL, $context=NULL) /** - * This function makes a role-assignment (a role for a user or group in a particular context) + * This function makes a role-assignment (a role for a user in a particular context) * * @param int $roleid the role of the id * @param int $userid userid - * @param int $groupid_ignored - never implemented! * @param int $contextid id of the context - * @param int $timestart time this assignment becomes effective defaults to 0 - * @param int $timeend time this assignment ceases to be effective defaults to 0 - * @param int $hidden_ignored - use roels with moodle/course:view capability or enrolment instead - * @param string $enrol defaults to 'manual' - * @param string $timemodified defaults to '' - * @return int new id of the assignment + * @param string $component example 'enrol_ldap', defaults to '' which means manual assignment, + * @prama int $itemid id of enrolment/auth plugin + * @param string $timemodified defaults to current time + * @return int new/existing id of the assignment */ -function role_assign($roleid, $userid, $groupid_ignored, $contextid, $timestart=0, $timeend=0, $hidden_ignored=0, $enrol='manual',$timemodified='') { +function role_assign($roleid, $userid, $contextid, $component = '', $itemid = 0, $timemodified = '') { global $USER, $CFG, $DB; -/// Do some data validation + // first of all detect if somebody is using old style parameters + if ($contextid === 0 or is_numeric($component)) { + throw new coding_exception('Invalid call to role_assign(), code needs to be updated to use new order of parameters'); + } + // now validate all parameters if (empty($roleid)) { - debugging('Role ID not provided'); - return false; + throw new coding_exception('Invalid call to role_assign(), roleid can not be empty'); } if (empty($userid)) { - debugging('Userid or groupid must be provided'); + throw new coding_exception('Invalid call to role_assign(), userid can not be empty'); + } + + if ($itemid) { + if (strpos($component, '_') === false) { + throw new coding_exception('Invalid call to role_assign(), component must start with plugin type such as"enrol_" when itemid specified', 'component:'.$component); + } + } else { + $itemid = 0; + if ($component !== '' and strpos($component, '_') === false) { + throw new coding_exception('Invalid call to role_assign(), invalid component string', 'component:'.$component); + } + } + + if (!$DB->record_exists('user', array('id'=>$userid, 'deleted'=>0))) { + throw new coding_exception('User ID does not exist or is deleted!', 'userid:'.$userid); return false; } - if ($userid && !$DB->record_exists('user', array('id'=>$userid))) { - debugging('User ID '.intval($userid).' does not exist!'); - return false; - } - - if (!$context = get_context_instance_by_id($contextid)) { - debugging('Context ID '.intval($contextid).' does not exist!'); - return false; - } - - if (($timestart and $timeend) and ($timestart > $timeend)) { - debugging('The end time can not be earlier than the start time'); - return false; - } + $context = get_context_instance_by_id($contextid, MUST_EXIST); if (!$timemodified) { $timemodified = time(); } /// Check for existing entry - $ra = $DB->get_record('role_assignments', array('roleid'=>$roleid, 'contextid'=>$context->id, 'userid'=>$userid)); + $ras = $DB->get_records('role_assignments', array('roleid'=>$roleid, 'contextid'=>$context->id, 'userid'=>$userid, 'component'=>$component, 'itemid'=>$itemid), 'id'); - if (empty($ra)) { // Create a new entry - $ra = new object(); - $ra->roleid = $roleid; - $ra->contextid = $context->id; - $ra->userid = $userid; - $ra->enrol = $enrol; - /// Always round timestart downto 100 secs to help DBs to use their own caching algorithms - /// by repeating queries with the same exact parameters in a 100 secs time window - $ra->timestart = round($timestart, -2); - $ra->timeend = $timeend; - $ra->timemodified = $timemodified; - $ra->modifierid = empty($USER->id) ? 0 : $USER->id; + if ($ras) { + // role already assigned - this should not happen + if (count($ras) > 1) { + //very weird - remove all duplicates! + $ra = array_shift($ras); + foreach ($ras as $r) { + $DB->delete_records('role_assignments', array('id'=>$r->id)); + } + } else { + $ra = reset($ras); + } - $ra->id = $DB->insert_record('role_assignments', $ra); - - } else { // We already have one, just update it - $ra->id = $ra->id; - $ra->enrol = $enrol; - /// Always round timestart downto 100 secs to help DBs to use their own caching algorithms - /// by repeating queries with the same exact parameters in a 100 secs time window - $ra->timestart = round($timestart, -2); - $ra->timeend = $timeend; - $ra->timemodified = $timemodified; - $ra->modifierid = empty($USER->id) ? 0 : $USER->id; - - $DB->update_record('role_assignments', $ra); + // actually there is no need to update, reset anything or trigger any event, so just return + return $ra->id; } -/// mark context as dirty - modules might use has_capability() in xxx_role_assing() -/// again expensive, but needed + // Create a new entry + $ra = new object(); + $ra->roleid = $roleid; + $ra->contextid = $context->id; + $ra->userid = $userid; + $ra->component = $component; + $ra->itemid = $itemid; + $ra->timemodified = $timemodified; + $ra->modifierid = empty($USER->id) ? 0 : $USER->id; + + $ra->id = $DB->insert_record('role_assignments', $ra); + + // mark context as dirty - again expensive, but needed mark_context_dirty($context->path); if (!empty($USER->id) && $USER->id == $userid) { -/// If the user is the current user, then do full reload of capabilities too. + // If the user is the current user, then do full reload of capabilities too. load_all_capabilities(); } -/// Ask all the modules if anything needs to be done for this user - $mods = get_plugin_list('mod'); - foreach ($mods as $mod => $moddir) { - include_once($moddir.'/lib.php'); - $functionname = $mod.'_role_assign'; - if (function_exists($functionname)) { - $functionname($userid, $context, $roleid); - } - } - - /// now handle metacourse role assignments if in course context - if ($context->contextlevel == CONTEXT_COURSE) { - if ($parents = $DB->get_records('course_meta', array('child_course'=>$context->instanceid))) { - foreach ($parents as $parent) { - sync_metacourse($parent->parent_course); - } - } - } - events_trigger('role_assigned', $ra); return $ra->id; } - /** - * Deletes one or more role assignments. You must specify at least one parameter. + * Removes one role assignment * - * @global object - * @global object - * @global object - * @param int $roleid defaults to 0 - * @param int $userid defaults to 0 - * @param int $groupid_ignored never implemented - * @param int $contextid defaults to 0 - * @param mixed $enrol unassign only if enrolment type matches, NULL means anything. Defaults to NULL - * @return boolean success or failure + * @param int $roleid + * @param int $userid + * @param int $contextid + * @param string $component + * @param int $itemid + * @return void */ -function role_unassign($roleid=0, $userid=0, $groupid_ignored=0, $contextid=0, $enrol=NULL) { - +function role_unassign($roleid, $userid, $contextid, $component = '', $itemid = 0) { global $USER, $CFG, $DB; - require_once($CFG->dirroot.'/group/lib.php'); - $args = array('roleid', 'userid', 'contextid'); - $select = array(); - $params = array(); + // first make sure the params make sense + if ($roleid == 0 or $userid == 0 or $contextid == 0) { + throw new coding_exception('Invalid call to role_unassign(), please use role_unassign_all() when removing multiple role assignments'); + } - foreach ($args as $arg) { - if ($$arg) { - $select[] = "$arg = ?"; - $params[] = $$arg; + if ($itemid) { + if (strpos($component, '_') === false) { + throw new coding_exception('Invalid call to role_assign(), component must start with plugin type such as "enrol_" when itemid specified', 'component:'.$component); + } + } else { + $itemid = 0; + if ($component !== '' and strpos($component, '_') === false) { + throw new coding_exception('Invalid call to role_assign(), invalid component string', 'component:'.$component); } } - if (!empty($enrol)) { - $select[] = "enrol=?"; - $params[] = $enrol; + + role_unassign_all(array('roleid'=>$roleid, 'userid'=>$userid, 'contextid'=>$contextid, 'component'=>$component, 'itemid'=>$itemid), false, false); +} + +/** + * Removes multiple role assignments, parameters may contain: + * 'roleid', 'userid', 'contextid', 'component', 'enrolid'. + * + * @param array $params role assignment parameters + * @param bool $subcontexts unassign in subcontexts too + * @param bool $includmanual include manual role assignments too + * @return void + */ +function role_unassign_all(array $params, $subcontexts = false, $includemanual=false) { + global $USER, $CFG, $DB; + + if (!$params) { + throw new coding_exception('Missing parameters in role_unsassign_all() call'); } - if ($select) { - if ($ras = $DB->get_records_select('role_assignments', implode(' AND ', $select), $params)) { - $mods = get_plugin_list('mod'); + $allowed = array('roleid', 'userid', 'contextid', 'component', 'itemid'); + foreach ($params as $key=>$value) { + if (!in_array($key, $allowed)) { + throw new coding_exception('Unknown role_unsassign_all() parameter key', 'key:'.$key); + } + } + + if (isset($params['component']) and $params['component'] !== '' and strpos($params['component'], '_') === false) { + throw new coding_exception('Invalid component paramter in role_unsassign_all() call', 'component:'.$params['component']); + } + + if ($includemanual) { + if (!isset($params['component']) or $params['component'] === '') { + throw new coding_exception('include manual parameter requires component parameter in role_unsassign_all() call'); + } + } + + if ($subcontexts) { + if (empty($params['contextid'])) { + throw new coding_exception('subcontexts paramtere requires component parameter in role_unsassign_all() call'); + } + } + + $ras = $DB->get_records('role_assignments', $params); + foreach($ras as $ra) { + $DB->delete_records('role_assignments', array('id'=>$ra->id)); + if ($context = get_context_instance_by_id($ra->contextid)) { + // this is a bit expensive but necessary + mark_context_dirty($context->path); + /// If the user is the current user, then do full reload of capabilities too. + if (!empty($USER->id) && $USER->id == $ra->userid) { + load_all_capabilities(); + } + } + events_trigger('role_unassigned', $ra); + } + unset($ras); + + // process subcontexts + if ($subcontexts and $context = get_context_instance_by_id($params['contextid'])) { + $contexts = get_child_contexts($context); + $mparams = $params; + foreach($contexts as $context) { + $mparams['contextid'] = $context->id; + $ras = $DB->get_records('role_assignments', $mparams); foreach($ras as $ra) { - /// infinite loop protection when deleting recursively - if (!$ra = $DB->get_record('role_assignments', array('id'=>$ra->id))) { - continue; - } $DB->delete_records('role_assignments', array('id'=>$ra->id)); - - if (!$context = get_context_instance_by_id($ra->contextid)) { - // strange error, not much to do - continue; - } - - /* mark contexts as dirty here, because we need the refreshed - * caps bellow to delete group membership and user_lastaccess! - * and yes, this is very expensive for bulk operations :-( - */ + // this is a bit expensive but necessary mark_context_dirty($context->path); - /// If the user is the current user, then do full reload of capabilities too. if (!empty($USER->id) && $USER->id == $ra->userid) { load_all_capabilities(); } - - /// Ask all the modules if anything needs to be done for this user - foreach ($mods as $mod=>$moddir) { - include_once($moddir.'/lib.php'); - $functionname = $mod.'_role_unassign'; - if (function_exists($functionname)) { - $functionname($ra->userid, $context); // watch out, $context might be NULL if something goes wrong - } - } - - /// now handle metacourse role unassigment and removing from groups if in course context - if ($context->contextlevel == CONTEXT_COURSE) { - - // cleanup leftover course groups/subscriptions etc when user has - // no capability to view course - // this may be slow, but this is the proper way of doing it - if (!has_capability('moodle/course:participate', $context, $ra->userid)) { - // remove from groups - groups_delete_group_members($context->instanceid, $ra->userid); - - // delete lastaccess records - $DB->delete_records('user_lastaccess', array('userid'=>$ra->userid, 'courseid'=>$context->instanceid)); - } - - //unassign roles in metacourses if needed - if ($parents = $DB->get_records('course_meta', array('child_course'=>$context->instanceid))) { - foreach ($parents as $parent) { - sync_metacourse($parent->parent_course); - } - } - } - events_trigger('role_unassigned', $ra); } } } - return true; + // do this once more for all manual role assignments + if ($includemanual) { + $params['component'] = ''; + role_unassign_all($params, $subcontexts, false); + } } -/** - * Enrol someone without using the default role in a course - * - * A convenience function to take care of the common case where you - * just want to enrol someone using the default role into a course - * - * @param object $course - * @param object $user - * @param string $enrol the plugin used to do this enrolment - * @return bool - */ -function enrol_into_course($course, $user, $enrol) { - - $timestart = time(); - // remove time part from the timestamp and keep only the date part - $timestart = make_timestamp(date('Y', $timestart), date('m', $timestart), date('d', $timestart), 0, 0, 0); - if ($course->enrolperiod) { - $timeend = $timestart + $course->enrolperiod; - } else { - $timeend = 0; - } - - if ($role = get_default_course_role($course)) { - - $context = get_context_instance(CONTEXT_COURSE, $course->id); - - if (!role_assign($role->id, $user->id, 0, $context->id, $timestart, $timeend, 0, $enrol)) { - return false; - } - - // force accessdata refresh for users visiting this context... - mark_context_dirty($context->path); - - email_welcome_message_to_user($course, $user); - - add_to_log($course->id, 'course', 'enrol', - 'view.php?id='.$course->id, $course->id); - - return true; - } - - return false; -} /** * Determines if a user is currently logged in @@ -2939,7 +2661,7 @@ function isloggedin() { /** * Determines if a user is logged in as real guest user with username 'guest'. * - * @param int $user mixed user object or id, $USER if not specified + * @param int|object $user mixed user object or id, $USER if not specified * @return bool true if user is the real guest user, false if not logged in or other user */ function isguestuser($user = NULL) { @@ -3004,7 +2726,8 @@ function is_guest($context, $user = NULL) { return false; } - if (has_capability('moodle/course:participate', $coursecontext, $userid, false)) { + // consider only real active enrolments here + if (is_enrolled($coursecontext, $user, '', true)) { return false; } @@ -3052,10 +2775,11 @@ function is_viewing($context, $user = NULL, $withcapability = '') { * @param object $context * @param int|object $user, if NULL $USER is used, otherwise user object or id expected * @param string $withcapability extra capability name + * @param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions * @return bool */ -function is_enrolled($context, $user = NULL, $withcapability = '') { - global $USER; +function is_enrolled($context, $user = NULL, $withcapability = '', $onlyactive = false) { + global $USER, $DB; // first find the course context $coursecontext = get_course_context($context); @@ -3075,9 +2799,47 @@ function is_enrolled($context, $user = NULL, $withcapability = '') { return false; } - if ($coursecontext->instanceid != SITEID and !has_capability('moodle/course:participate', $coursecontext, $userid, false)) { - // admins are not enrolled, everybody is "enrolled" in the frontpage course - return false; + if ($coursecontext->instanceid == SITEID) { + // everybody participates on frontpage + } else { + if ($onlyactive) { + $sql = "SELECT ue.* + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid) + JOIN {user} u ON u.id = ue.userid + WHERE ue.userid = :userid AND ue.status = :active AND e.status = :enabled AND u.deleted = 0"; + $params = array('enabled'=>ENROL_INSTANCE_ENABLED, 'active'=>ENROL_USER_ACTIVE, 'userid'=>$userid, 'courseid'=>$coursecontext->instanceid); + // this result should be very small, better not do the complex time checks in sql for now ;-) + $enrolments = $DB->get_records_sql($sql, $params); + $now = time(); + // make sure the enrol period is ok + $result = false; + foreach ($enrolments as $e) { + if ($e->timestart > $now) { + continue; + } + if ($e->timeend and $e->timeend < $now) { + continue; + } + $result = true; + break; + } + if (!$result) { + return false; + } + + } else { + // any enrolment is good for us here, even outdated, disabled or inactive + $sql = "SELECT 'x' + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid) + JOIN {user} u ON u.id = ue.userid + WHERE ue.userid = :userid AND u.deleted = 0"; + $params = array('userid'=>$userid, 'courseid'=>$coursecontext->instanceid); + if (!$DB->record_exists_sql($sql, $params)) { + return false; + } + } } if ($withcapability and !has_capability($withcapability, $context, $userid)) { @@ -3090,144 +2852,88 @@ function is_enrolled($context, $user = NULL, $withcapability = '') { /** * Returns array with sql code and parameters returning all ids * of users enrolled into course. + * + * This function is using 'eu[0-9]+_' prefix for table names and parameters. + * * @param object $context * @param string $withcapability * @param int $groupid 0 means ignore groups, any other value limits the result by group id - * @param string $prefix used for alias of user table, parameter names and in aliases of other used tables + * @param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions * @return array list($sql, $params) */ -function get_enrolled_sql($context, $withcapability = '', $groupid = 0, $prefix = 'eu') { +function get_enrolled_sql($context, $withcapability = '', $groupid = 0, $onlyactive = false) { global $DB; - if ($context->contextlevel < CONTEXT_COURSE) { - throw new coding_exception('get_enrolled_sql() expects course context and bellow!'); - } + // use unique prefix just in case somebody makes some SQL magic with the result + static $i = 0; + $i++; + $prefix = 'eu'.$i.'_'; // first find the course context - if ($context->contextlevel == CONTEXT_COURSE) { - $coursecontext = $context; - - } else if ($context->contextlevel == CONTEXT_MODULE) { - $coursecontext = get_context_instance_by_id(get_parent_contextid($context, MUST_EXIST)); - - } else if ($context->contextlevel == CONTEXT_BLOCK) { - $parentcontext = get_context_instance_by_id(get_parent_contextid($context, MUST_EXIST)); - if ($parentcontext->contextlevel == CONTEXT_COURSE) { - $coursecontext = $parentcontext; - } else if ($parentcontext->contextlevel == CONTEXT_MODULE) { - $coursecontext = get_context_instance_by_id(get_parent_contextid($parentcontext, MUST_EXIST)); - } else { - throw new coding_exception('Invalid context supplied to get_enrolled_sql()!'); - } - - } else { - throw new coding_exception('Invalid context supplied to get_enrolled_sql()!'); - } - - list($contextids, $contextpaths) = get_context_info_list($context); - list($coursecontextids, $coursecontextpaths) = get_context_info_list($coursecontext); - - // get all relevant capability info for all roles - if ($withcapability) { - list($incontexts, $params) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'con00'); - $incaps = "IN (:participate, :withcap)"; - $params['participate'] = 'moodle/course:participate'; - $params['withcap'] = $withcapability; - } else { - list($incontexts, $params) = $DB->get_in_or_equal($coursecontextids, SQL_PARAMS_NAMED, 'con00'); - $incaps = "= :participate"; - $params['participate'] = 'moodle/course:participate'; - } - $defs = array(); - $sql = "SELECT rc.id, rc.roleid, rc.permission, rc.capability, ctx.path - FROM {role_capabilities} rc - JOIN {context} ctx on rc.contextid = ctx.id - WHERE rc.contextid $incontexts AND rc.capability $incaps"; - $rcs = $DB->get_records_sql($sql, $params); - foreach ($rcs as $rc) { - $defs[$rc->capability][$rc->path][$rc->roleid] = $rc->permission; - } - - $courseaccess = array(); - if (!empty($defs['moodle/course:participate'])) { - foreach ($coursecontextpaths as $path) { - if (empty($defs['moodle/course:participate'][$path])) { - continue; - } - - foreach($defs['moodle/course:participate'][$path] as $roleid => $perm) { - if ($perm == CAP_PROHIBIT) { - $courseaccess[$roleid] = CAP_PROHIBIT; - continue; - } - if (!isset($courseaccess[$roleid])) { - $courseaccess[$roleid] = (int)$perm; - } - } - } - } - - $access = array(); - if (!empty($defs[$withcapability])) { - foreach ($contextpaths as $path) { - if (empty($defs[$withcapability][$path])) { - continue; - } - foreach($defs[$withcapability][$path] as $roleid => $perm) { - if ($perm == CAP_PROHIBIT) { - $access[$roleid] = CAP_PROHIBIT; - continue; - } - if (!isset($access[$roleid])) { - $access[$roleid] = (int)$perm; - } - } - } - } - - unset($defs); - - // make lists of roles that are needed and prohibited - $courseneeded = array(); // one of these is enough - $courseprohibited = array(); // must not have any of these - foreach ($courseaccess as $roleid => $perm) { - if ($perm == CAP_PROHIBIT) { - unset($courseneeded[$roleid]); - $courseprohibited[$roleid] = true; - } else if ($perm == CAP_ALLOW and empty($courseprohibited[$roleid])) { - $courseneeded[$roleid] = true; - } - } - $needed = array(); // one of these is enough - $prohibited = array(); // must not have any of these - if ($withcapability) { - foreach ($access as $roleid => $perm) { - if ($perm == CAP_PROHIBIT) { - unset($needed[$roleid]); - $prohibited[$roleid] = true; - } else if ($perm == CAP_ALLOW and empty($prohibited[$roleid])) { - $needed[$roleid] = true; - } - } - } + $coursecontext = get_course_context($context); $isfrontpage = ($coursecontext->instanceid == SITEID); - $defaultuserroleid = isset($CFG->defaultuserroleid) ? $CFG->defaultuserroleid : NULL; - $defaultfrontpageroleid = isset($CFG->defaultfrontpageroleid) ? $CFG->defaultfrontpageroleid : NULL; + $joins = array(); + $wheres = array(); + $params = array(); - $nobody = false; + list($contextids, $contextpaths) = get_context_info_list($context); - if ($isfrontpage) { - // on the frontpage all users are kind of enrolled, we have to respect only the prohibits - $courseneeded = array(); - } else { - if (empty($courseneeded)) { - $nobody = true; + // get all relevant capability info for all roles + if ($withcapability) { + list($incontexts, $cparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'ctx00'); + $cparams['cap'] = $withcapability; + + $defs = array(); + $sql = "SELECT rc.id, rc.roleid, rc.permission, ctx.path + FROM {role_capabilities} rc + JOIN {context} ctx on rc.contextid = ctx.id + WHERE rc.contextid $incontexts AND rc.capability = :cap"; + $rcs = $DB->get_records_sql($sql, $cparams); + foreach ($rcs as $rc) { + $defs[$rc->path][$rc->roleid] = $rc->permission; } - } - if ($withcapability and !$nobody) { + $access = array(); + if (!empty($defs)) { + foreach ($contextpaths as $path) { + if (empty($defs[$path])) { + continue; + } + foreach($defs[$path] as $roleid => $perm) { + if ($perm == CAP_PROHIBIT) { + $access[$roleid] = CAP_PROHIBIT; + continue; + } + if (!isset($access[$roleid])) { + $access[$roleid] = (int)$perm; + } + } + } + } + + unset($defs); + + // make lists of roles that are needed and prohibited + $needed = array(); // one of these is enough + $prohibited = array(); // must not have any of these + if ($withcapability) { + foreach ($access as $roleid => $perm) { + if ($perm == CAP_PROHIBIT) { + unset($needed[$roleid]); + $prohibited[$roleid] = true; + } else if ($perm == CAP_ALLOW and empty($prohibited[$roleid])) { + $needed[$roleid] = true; + } + } + } + + $defaultuserroleid = isset($CFG->defaultuserroleid) ? $CFG->defaultuserroleid : NULL; + $defaultfrontpageroleid = isset($CFG->defaultfrontpageroleid) ? $CFG->defaultfrontpageroleid : NULL; + + $nobody = false; + if ($isfrontpage) { if (!empty($prohibited[$defaultuserroleid]) or !empty($prohibited[$defaultfrontpageroleid])) { $nobody = true; @@ -3247,53 +2953,58 @@ function get_enrolled_sql($context, $withcapability = '', $groupid = 0, $prefix $nobody = true; } } + + if ($nobody) { + // nobody can match so return some SQL that does not return any results + $wheres[] = "1 = 2"; + + } else { + + if ($needed) { + $ctxids = implode(',', $contextids); + $roleids = implode(',', array_keys($needed)); + $joins[] = "JOIN {role_assignments} {$prefix}ra3 ON ({$prefix}ra3.userid = {$prefix}u.id AND {$prefix}ra3.roleid IN ($roleids) AND {$prefix}ra3.contextid IN ($ctxids))"; + } + + if ($prohibited) { + $ctxids = implode(',', $contextids); + $roleids = implode(',', array_keys($prohibited)); + $joins[] = "LEFT JOIN {role_assignments} {$prefix}ra4 ON ({$prefix}ra4.userid = {$prefix}u.id AND {$prefix}ra4.roleid IN ($roleids) AND {$prefix}ra4.contextid IN ($ctxids))"; + $wheres[] = "{$prefix}ra4 IS NULL"; + } + + if ($groupid) { + $joins[] = "JOIN {groups_members} {$prefix}gm ON ({$prefix}gm.userid = {$prefix}u.id AND {$prefix}gm.id = :{$prefix}gmid)"; + $params["{$prefix}gmid"] = $groupid; + } + } + } - if ($nobody) { - // nobody can match so return some SQL that does not return any results - return array("SELECT {$prefix}.id FROM {user} {$prefix} WHERE 1=2", array()); - } + $wheres[] = "{$prefix}u.deleted = 0 AND {$prefix}u.username <> 'guest'"; - $joins = array(); - $params = array(); - $wheres = array("{$prefix}.deleted = 0 AND {$prefix}.username <> 'guest'"); + if ($isfrontpage) { + // all users are "enrolled" on the frontpage + } else { + $joins[] = "JOIN {user_enrolments} {$prefix}ue ON {$prefix}ue.userid = {$prefix}u.id"; + $joins[] = "JOIN {enrol} {$prefix}e ON ({$prefix}e.id = {$prefix}ue.enrolid AND {$prefix}e.courseid = :{$prefix}courseid)"; + $params[$prefix.'courseid'] = $coursecontext->instanceid; - if ($courseneeded) { - $ctxids = implode(',', $coursecontextids); - $roleids = implode(',', array_keys($courseneeded)); - $joins[] = "JOIN {role_assignments} {$prefix}_ra1 ON ({$prefix}_ra1.userid = {$prefix}.id AND {$prefix}_ra1.roleid IN ($roleids) AND {$prefix}_ra1.contextid IN ($ctxids))"; - } - - if ($courseprohibited) { - $ctxids = implode(',', $coursecontextids); - $roleids = implode(',', array_keys($courseprohibited)); - $joins[] = "LEFT JOIN {role_assignments} {$prefix}_ra2 ON ({$prefix}_ra2.userid = {$prefix}.id AND {$prefix}_ra2.roleid IN ($roleids) AND {$prefix}_ra2.contextid IN ($ctxids))"; - $wheres[] = "{$prefix}_ra2 IS NULL"; - } - - if ($needed) { - $ctxids = implode(',', $contextids); - $roleids = implode(',', array_keys($needed)); - $joins[] = "JOIN {role_assignments} {$prefix}_ra3 ON ({$prefix}_ra3.userid = {$prefix}.id AND {$prefix}_ra3.roleid IN ($roleids) AND {$prefix}_ra3.contextid IN ($ctxids))"; - } - - if ($prohibited) { - $ctxids = implode(',', $contextids); - $roleids = implode(',', array_keys($prohibited)); - $joins[] = "LEFT JOIN {role_assignments} {$prefix}_ra4 ON ({$prefix}_ra4.userid = {$prefix}.id AND {$prefix}_ra4.roleid IN ($roleids) AND {$prefix}_ra4.contextid IN ($ctxids))"; - $wheres[] = "{$prefix}_ra4 IS NULL"; - } - - if ($groupid) { - $joins[] = "JOIN {groups_members} {$prefix}gm ON ({$prefix}gm.userid = {$prefix}.id AND {$prefix}gm.id = :{$prefix}gmid)"; - $params["{$prefix}gmid"] = $groupid; + if ($onlyactive) { + $wheres[] = "{$prefix}ue.status = :{$prefix}active AND {$prefix}e.status = :{$prefix}enabled"; + $wheres[] = "{$prefix}ue.timestart < :{$prefix}now1 AND ({$prefix}ue.timeend = 0 OR {$prefix}ue.timeend > :{$prefix}now2)"; + $now = round(time(), -2); // rounding helps caching in DB + $params = array_merge($params, array($prefix.'enabled'=>ENROL_INSTANCE_ENABLED, + $prefix.'active'=>ENROL_USER_ACTIVE, + $prefix.'now1'=>$now, $prefix.'now2'=>$now)); + } } $joins = implode("\n", $joins); $wheres = "WHERE ".implode(" AND ", $wheres); - $sql = "SELECT DISTINCT {$prefix}.id - FROM {user} {$prefix} + $sql = "SELECT DISTINCT {$prefix}u.id + FROM {user} {$prefix}u $joins $wheres"; @@ -4011,7 +3722,7 @@ function get_context_info_list($context) { */ function get_course_context($context) { if (empty($context->contextlevel)) { - throw coding_exception('Invalid context parameter.'); + throw new coding_exception('Invalid context parameter.'); } if ($context->contextlevel == CONTEXT_COURSE) { return $context; @@ -4334,7 +4045,7 @@ function get_component_string($component, $contextlevel) { case CONTEXT_SYSTEM: if (preg_match('|^enrol|', $component)) { $langname = str_replace('/', '_', $component); - $string = get_string('enrolname', $langname); + $string = get_string('pluginname', $langname); } else if (preg_match('|^block|', $component)) { $langname = str_replace('/', '_', $component); $string = get_string('pluginname', $langname); @@ -4355,11 +4066,19 @@ function get_component_string($component, $contextlevel) { break; case CONTEXT_COURSECAT: - $string = get_string('categories'); + if (preg_match('|^enrol|', $component)) { + $langname = str_replace('/', '_', $component); + $string = get_string('pluginname', $langname); + } else { + $string = get_string('categories'); + } break; case CONTEXT_COURSE: - if (preg_match('|^gradeimport|', $component)) { + if (preg_match('|^enrol|', $component)) { + $langname = str_replace('/', '_', $component); + $string = get_string('pluginname', $langname); + } else if (preg_match('|^gradeimport|', $component)) { $string = get_string('gradeimport', 'grades').': '.get_string('modulename', $component); } else if (preg_match('|^gradeexport|', $component)) { $string = get_string('gradeexport', 'grades').': '.get_string('modulename', $component); @@ -4555,7 +4274,7 @@ function get_all_roles() { */ function get_archetype_roles($archetype) { global $DB; - return $DB->get_records('role', array('archetype'=>$archetype)); + return $DB->get_records('role', array('archetype'=>$archetype), 'sortorder ASC'); } /** @@ -4656,8 +4375,6 @@ function allow_switch($fromroleid, $targetroleid) { /** * Gets a list of roles that this user can assign in this context * - * @global object - * @global object * @param object $context the context. * @param int $rolenamedisplay the type of role name to display. One of the * ROLENAME_X constants. Default ROLENAME_ALIAS. @@ -4682,7 +4399,7 @@ function get_assignable_roles($context, $rolenamedisplay = ROLENAME_ALIAS, $with $params = array(); $extrafields = ''; - if ($rolenamedisplay == ROLENAME_ORIGINALANDSHORT) { + if ($rolenamedisplay == ROLENAME_ORIGINALANDSHORT or $rolenamedisplay == ROLENAME_SHORT) { $extrafields .= ', r.shortname'; } @@ -4716,12 +4433,16 @@ function get_assignable_roles($context, $rolenamedisplay = ROLENAME_ALIAS, $with $rolenames = array(); foreach ($roles as $role) { + if ($rolenamedisplay == ROLENAME_SHORT) { + $rolenames[$role->id] = $role->shortname; + continue; + } $rolenames[$role->id] = $role->name; if ($rolenamedisplay == ROLENAME_ORIGINALANDSHORT) { $rolenames[$role->id] .= ' (' . $role->shortname . ')'; } } - if ($rolenamedisplay != ROLENAME_ORIGINALANDSHORT) { + if ($rolenamedisplay != ROLENAME_ORIGINALANDSHORT and $rolenamedisplay != ROLENAME_SHORT) { $rolenames = role_fix_names($rolenames, $context, $rolenamedisplay); } @@ -4759,8 +4480,7 @@ function get_switchable_roles($context) { $extrajoins = ''; $extrawhere = ''; if (!is_siteadmin()) { - // Admins are allowed to switch to any role with 'moodle/course:participate' in the - // role definition. + // Admins are allowed to switch to any role with. // Others are subject to the additional constraint that the switch-to role must be allowed by // 'role_allow_switch' for some role they have assigned in this context or any parent. $parents = get_parent_contexts($context); @@ -4769,7 +4489,7 @@ function get_switchable_roles($context) { $extrajoins = "JOIN {role_allow_switch} ras ON ras.allowswitch = rc.roleid JOIN {role_assignments} ra ON ra.roleid = ras.roleid"; - $extrawhere = "AND ra.userid = :userid AND ra.contextid IN ($contexts)"; + $extrawhere = "WHERE ra.userid = :userid AND ra.contextid IN ($contexts)"; $params['userid'] = $USER->id; } @@ -4779,46 +4499,15 @@ function get_switchable_roles($context) { SELECT DISTINCT rc.roleid FROM {role_capabilities} rc $extrajoins - WHERE rc.capability = :viewcap - AND rc.permission = " . CAP_ALLOW . " - AND rc.contextid = :syscontextid - $extrawhere + $extrawhere ) idlist JOIN {role} r ON r.id = idlist.roleid ORDER BY r.sortorder"; - $params['syscontextid'] = $systemcontext->id; - $params['viewcap'] = 'moodle/course:participate'; $rolenames = $DB->get_records_sql_menu($query, $params); return role_fix_names($rolenames, $context, ROLENAME_ALIAS); } -/** - * Get an array of role ids that might possibly be the target of a switchrole. - * Our policy is that you cannot switch to admin role - * and you can only switch to a role with moodle/course:participate. This method returns - * a list of those role ids. - * - * @global object - * @return array an array whose keys are the allowed role ids. - */ -function get_allowed_switchable_roles() { - global $CFG, $DB; - - $systemcontext = get_context_instance(CONTEXT_SYSTEM); - - $query = " - SELECT DISTINCT rc.roleid, 1 - FROM {role_capabilities} rc - JOIN {role} r ON r.id = rc.roleid - WHERE rc.capability = :participate - AND rc.permission = " . CAP_ALLOW . " - AND rc.contextid = :syscontextid"; - $params = array('syscontextid' => $systemcontext->id, 'participate' => 'moodle/course:participate'); - - return $DB->get_records_sql_menu($query, $params); -} - /** * Gets a list of roles that this user can override in this context. * @@ -4904,6 +4593,34 @@ function get_overridable_roles($context, $rolenamedisplay = ROLENAME_ALIAS, $wit return array($rolenames, $rolecounts, $nameswithcounts); } +/** + * Create a role menu suitable for default role selection in enrol plugins. + * @param object $context + * @param int $addroleid current or default role - always added to list + * @return array roleid=>localised role name + */ +function get_default_enrol_roles($context, $addroleid = null) { + global $DB; + + $params = array('level'=>CONTEXT_COURSE); + if ($addroleid) { + $addrole = "OR r.id = :addroleid"; + $params['addroleid'] = $addroleid; + } else { + $addrole = ""; + } + $sql = "SELECT r.id, r.name + FROM {role} r + LEFT JOIN {role_context_levels} rcl ON (rcl.roleid = r.id AND rcl.contextlevel = :level) + WHERE rcl.id IS NOT NULL $addrole + ORDER BY sortorder DESC"; + + $roles = $DB->get_records_sql_menu($sql, $params); + $roles = role_fix_names($roles, $context, ROLENAME_BOTH); + + return $roles; +} + /** * @global object * @param integer $roleid the id of a role. @@ -4933,15 +4650,15 @@ function get_roles_for_contextlevels($contextlevel) { */ function get_default_contextlevels($rolearchetype) { static $defaults = array( - 'manager' => array(CONTEXT_SYSTEM, CONTEXT_COURSECAT, CONTEXT_COURSE), - 'coursecreator' => array(CONTEXT_SYSTEM, CONTEXT_COURSECAT), - 'editingteacher' => array(CONTEXT_COURSECAT, CONTEXT_COURSE, CONTEXT_MODULE), - 'teacher' => array(CONTEXT_COURSECAT, CONTEXT_COURSE, CONTEXT_MODULE), - 'student' => array(CONTEXT_COURSE, CONTEXT_MODULE), - 'guest' => array(), - 'user' => array(), - 'frontpage' => array() - ); + 'manager' => array(CONTEXT_SYSTEM, CONTEXT_COURSECAT, CONTEXT_COURSE), + 'coursecreator' => array(CONTEXT_SYSTEM, CONTEXT_COURSECAT), + 'editingteacher' => array(CONTEXT_COURSE, CONTEXT_MODULE), + 'teacher' => array(CONTEXT_COURSE, CONTEXT_MODULE), + 'student' => array(CONTEXT_COURSE, CONTEXT_MODULE), + 'guest' => array(), + 'user' => array(), + 'frontpage' => array()); + if (isset($defaults[$rolearchetype])) { return $defaults[$rolearchetype]; } else { @@ -4955,54 +4672,22 @@ function get_default_contextlevels($rolearchetype) { * * @global object * @param integer $roleid the id of a role. - * @param array $contextlevels the context levels at which this role should be assignable. + * @param array $contextlevels the context levels at which this role should be assignable, + * duplicate levels are removed. + * @return void */ function set_role_contextlevels($roleid, array $contextlevels) { global $DB; $DB->delete_records('role_context_levels', array('roleid' => $roleid)); $rcl = new stdClass; $rcl->roleid = $roleid; + $contextlevels = array_unique($contextlevels); foreach ($contextlevels as $level) { $rcl->contextlevel = $level; $DB->insert_record('role_context_levels', $rcl, false, true); } } -/** - * Returns a role object that is the default role for new enrolments - * in a given course - * - * @global object - * @global object - * @param object $course - * @return object returns a role or NULL if none set - */ -function get_default_course_role($course) { - global $DB, $CFG; - -/// First let's take the default role the course may have - if (!empty($course->defaultrole)) { - if ($role = $DB->get_record('role', array('id'=>$course->defaultrole))) { - return $role; - } - } - -/// Otherwise the site setting should tell us - if ($CFG->defaultcourseroleid) { - if ($role = $DB->get_record('role', array('id'=>$CFG->defaultcourseroleid))) { - return $role; - } - } - -/// It's unlikely we'll get here, but just in case, try and find a student role - if ($studentroles = $DB->get_records('role', array('archetype'=>'student'))) { - return array_shift($studentroles); /// Take the first one - } - - return NULL; -} - - /** * Who has this capability in this context? * @@ -5302,7 +4987,7 @@ function get_users_by_capability($context, $capability, $fields='', $sort='', $l * a good idea to see what roles have the capabilities you want * (array_diff() them against roiles that have 'can-do-anything' * to weed out admin-ish roles. Or fetch a list of roles from - * variables like $CFG->coursemanager . + * variables like $CFG->coursecontact . * * @global object * @param array $users Users array, keyed on userid @@ -5387,7 +5072,7 @@ function get_role_users($roleid, $context, $parent=false, $fields='', $fields = 'u.id, u.confirmed, u.username, u.firstname, u.lastname, '. 'u.maildisplay, u.mailformat, u.maildigest, u.email, u.city, '. 'u.country, u.picture, u.idnumber, u.department, u.institution, '. - 'u.emailstop, u.lang, u.timezone, u.lastaccess, u.mnethostid, r.name as rolename'; + 'u.emailstop, u.lang, u.timezone, u.lastaccess, u.mnethostid, r.name AS rolename, r.sortorder'; } $parentcontexts = ''; @@ -5423,7 +5108,7 @@ function get_role_users($roleid, $context, $parent=false, $fields='', $params = array_merge($params, $whereparams); } - $sql = "SELECT $fields, ra.roleid + $sql = "SELECT DISTINCT $fields, ra.roleid FROM {role_assignments} ra JOIN {user} u ON u.id = ra.userid JOIN {role} r ON ra.roleid = r.id @@ -5819,10 +5504,6 @@ function role_fix_names($roleoptions, $context, $rolenamedisplay=ROLENAME_ALIAS) */ function component_level_changed($cap, $comp, $contextlevel) { - if ($cap->component == 'enrol/authorize' && $comp =='enrol/authorize') { - return false; - } - if (strstr($cap->component, '/') && strstr($comp, '/')) { $compsa = explode('/', $cap->component); $compsb = explode('/', $comp); diff --git a/lib/adminlib.php b/lib/adminlib.php index b526150db4b..90edf9b1696 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -139,12 +139,12 @@ function uninstall_plugin($type, $name) { if ($type === 'mod') { $pluginname = $name; // eg. 'forum' - $strpluginname = get_string('modulename', $pluginname); if (get_string_manager()->string_exists('modulename', $component)) { $strpluginname = get_string('modulename', $component); } else { $strpluginname = $component; } + } else { $pluginname = $component; if (get_string_manager()->string_exists('pluginname', $component)) { @@ -153,6 +153,7 @@ function uninstall_plugin($type, $name) { $strpluginname = $component; } } + echo $OUTPUT->heading($pluginname); $plugindirectory = get_plugin_directory($type, $name); @@ -167,7 +168,7 @@ function uninstall_plugin($type, $name) { } } - if ('mod' === $type) { + if ($type === 'mod') { // perform cleanup tasks specific for activity modules if (!$module = $DB->get_record('modules', array('name' => $name))) { @@ -221,6 +222,26 @@ function uninstall_plugin($type, $name) { } } } + + } else if ($type === 'enrol') { + // NOTE: this is a bit brute force way - it will not trigger events and hooks properly + // nuke all role assignments + role_unassign_all(array('component'=>$component)); + // purge participants + $DB->delete_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($name)); + // purge enrol instances + $DB->delete_records('enrol', array('enrol'=>$name)); + // tweak enrol settings + if (!empty($CFG->enrol_plugins_enabled)) { + $enabledenrols = explode(',', $CFG->enrol_plugins_enabled); + $enabledenrols = array_unique($enabledenrols); + $enabledenrols = array_flip($enabledenrols); + unset($enabledenrols[$name]); + $enabledenrols = array_flip($enabledenrols); + if (is_array($enabledenrols)) { + set_config('enrol_plugins_enabled', implode(',', $enabledenrols)); + } + } } // perform clean-up task common for all the plugin/subplugin types @@ -4238,13 +4259,13 @@ class admin_setting_regradingcheckbox extends admin_setting_configcheckbox { * * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class admin_setting_special_coursemanager extends admin_setting_pickroles { +class admin_setting_special_coursecontact extends admin_setting_pickroles { /** * Calls parent::__construct with specific arguments */ public function __construct() { - parent::__construct('coursemanager', get_string('coursemanager', 'admin'), - get_string('configcoursemanager', 'admin'), + parent::__construct('coursecontact', get_string('coursecontact', 'admin'), + get_string('coursecontact_desc', 'admin'), array('editingteacher')); } } @@ -4613,66 +4634,204 @@ class admin_page_managemods extends admin_externalpage { } } + /** - * Enrolment manage page + * Special class for enrol plugins management. * + * @copyright 2010 Petr Skoda {@link http://skodak.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class admin_enrolment_page extends admin_externalpage { +class admin_setting_manageenrols extends admin_setting { /** * Calls parent::__construct with specific arguments */ public function __construct() { - global $CFG; - parent::__construct('enrolment', get_string('enrolments'), $CFG->wwwroot . '/'.$CFG->admin.'/enrol.php'); + $this->nosave = true; + parent::__construct('enrolsui', get_string('manageenrols', 'enrol'), '', ''); } /** - * @param string The string to search for - * @return array + * Always returns true, does nothing + * + * @return true */ - public function search($query) { - if ($result = parent::search($query)) { - return $result; + public function get_setting() { + return true; + } + + /** + * Always returns true, does nothing + * + * @return true + */ + public function get_defaultsetting() { + return true; + } + + /** + * Always returns '', does not write anything + * + * @return string Always returns '' + */ + public function write_setting($data) { + // do not write any setting + return ''; + } + + /** + * Checks if $query is one of the available enrol plugins + * + * @param string $query The string to search for + * @return bool Returns true if found, false if not + */ + public function is_related($query) { + if (parent::is_related($query)) { + return true; } - $found = false; - - if ($modules = get_plugin_list('enrol')) { - $textlib = textlib_get_instance(); - foreach ($modules as $plugin => $dir) { - if (strpos($plugin, $query) !== false) { - $found = true; - break; - } - $strmodulename = get_string('enrolname', "enrol_$plugin"); - if (strpos($textlib->strtolower($strmodulename), $query) !== false) { - $found = true; - break; - } + $textlib = textlib_get_instance(); + $query = $textlib->strtolower($query); + $enrols = enrol_get_plugins(false); + foreach ($enrols as $name=>$enrol) { + $localised = get_string('pluginname', 'enrol_'.$name); + if (strpos($textlib->strtolower($name), $query) !== false) { + return true; + } + if (strpos($textlib->strtolower($localised), $query) !== false) { + return true; } } - //ugly harcoded hacks - if (strpos('sendcoursewelcomemessage', $query) !== false) { - $found = true; - } else if (strpos($textlib->strtolower(get_string('sendcoursewelcomemessage', 'admin')), $query) !== false) { - $found = true; - } else if (strpos($textlib->strtolower(get_string('configsendcoursewelcomemessage', 'admin')), $query) !== false) { - $found = true; - } else if (strpos($textlib->strtolower(get_string('configenrolmentplugins', 'admin')), $query) !== false) { - $found = true; - } - if ($found) { - $result = new object(); - $result->page = $this; - $result->settings = array(); - return array($this->name => $result); - } else { - return array(); + return false; + } + + /** + * Builds the XHTML to display the control + * + * @param string $data Unused + * @param string $query + * @return string + */ + public function output_html($data, $query='') { + global $CFG, $OUTPUT, $DB; + + // display strings + $strup = get_string('up'); + $strdown = get_string('down'); + $strsettings = get_string('settings'); + $strenable = get_string('enable'); + $strdisable = get_string('disable'); + $struninstall = get_string('uninstallplugin', 'admin'); + $strusage = get_string('enrolusage', 'enrol'); + + $enrols_available = enrol_get_plugins(false); + $active_enrols = enrol_get_plugins(true); + + $allenrols = array(); + foreach ($active_enrols as $key=>$enrol) { + $allenrols[$key] = true; } + foreach ($enrols_available as $key=>$enrol) { + $allenrols[$key] = true; + } + // now find all borked plugins and at least allow then to uninstall + $borked = array(); + $condidates = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {enrol}"); + foreach ($condidates as $candidate) { + if (empty($allenrols[$candidate])) { + $allenrols[$candidate] = true; + } + } + + $return = $OUTPUT->heading(get_string('actenrolshhdr', 'enrol'), 3, 'main', true); + $return .= $OUTPUT->box_start('generalbox enrolsui'); + + $table = new html_table(); + $table->head = array(get_string('name'), $strusage, $strenable, $strup.'/'.$strdown, $strsettings, $struninstall); + $table->align = array('left', 'center', 'center', 'center', 'center', 'center'); + $table->width = '90%'; + $table->data = array(); + + // iterate through enrol plugins and add to the display table + $updowncount = 1; + $enrolcount = count($active_enrols); + $url = new moodle_url('/admin/enrol.php', array('sesskey'=>sesskey())); + $printed = array(); + foreach($allenrols as $enrol => $unused) { + if (get_string_manager()->string_exists('pluginname', 'enrol_'.$enrol)) { + $name = get_string('pluginname', 'enrol_'.$enrol); + } else { + $name = $enrol; + } + //usage + $ci = $DB->count_records('enrol', array('enrol'=>$enrol)); + $cp = $DB->count_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($enrol)); + $usage = "$ci / $cp"; + + // hide/show link + if (isset($active_enrols[$enrol])) { + $aurl = new moodle_url($url, array('action'=>'disable', 'enrol'=>$enrol)); + $hideshow = ""; + $hideshow .= "pix_url('i/hide') . "\" class=\"icon\" alt=\"$strdisable\" />"; + $enabled = true; + $displayname = "$name"; + } else if (isset($enrols_available[$enrol])) { + $aurl = new moodle_url($url, array('action'=>'enable', 'enrol'=>$enrol)); + $hideshow = ""; + $hideshow .= "pix_url('i/show') . "\" class=\"icon\" alt=\"$strenable\" />"; + $enabled = false; + $displayname = "$name"; + } else { + $hideshow = ''; + $enabled = false; + $displayname = ''.$name.''; + } + + // up/down link (only if enrol is enabled) + $updown = ''; + if ($enabled) { + if ($updowncount > 1) { + $aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol)); + $updown .= ""; + $updown .= "pix_url('t/up') . "\" alt=\"$strup\" /> "; + } else { + $updown .= "pix_url('spacer') . "\" class=\"icon\" alt=\"\" /> "; + } + if ($updowncount < $enrolcount) { + $aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol)); + $updown .= ""; + $updown .= "pix_url('t/down') . "\" alt=\"$strdown\" />"; + } else { + $updown .= "pix_url('spacer') . "\" class=\"icon\" alt=\"\" />"; + } + ++$updowncount; + } + + // settings link + if (isset($active_enrols[$enrol]) or file_exists($CFG->dirroot.'/enrol/'.$enrol.'/settings.php')) { + $surl = new moodle_url('/admin/settings.php', array('section'=>'enrolsettings'.$enrol)); + $settings = "$strsettings"; + } else { + $settings = ''; + } + + // uninstall + $aurl = new moodle_url($url, array('action'=>'uninstall', 'enrol'=>$enrol)); + $uninstall = "$struninstall"; + + // add a row to the table + $table->data[] = array($displayname, $usage, $hideshow, $updown, $settings, $uninstall); + + $printed[$enrol] = true; + } + + $return .= html_writer::table($table); + $return .= get_string('configenrolplugins', 'enrol').'
'.get_string('tablenosave', 'admin'); + $return .= $OUTPUT->box_end(); + return highlight($query, $return); } } + /** * Blocks manage page * @@ -4948,14 +5107,14 @@ class admin_setting_manageauths extends admin_setting { $updown .= "pix_url('t/up') . "\" alt=\"up\" /> "; } else { - $updown .= "pix_url('spacer.gif') . "\" class=\"icon\" alt=\"\" /> "; + $updown .= "pix_url('spacer') . "\" class=\"icon\" alt=\"\" /> "; } if ($updowncount < $authcount) { $updown .= ""; $updown .= "pix_url('t/down') . "\" alt=\"down\" />"; } else { - $updown .= "pix_url('spacer.gif') . "\" class=\"icon\" alt=\"\" />"; + $updown .= "pix_url('spacer') . "\" class=\"icon\" alt=\"\" />"; } ++ $updowncount; } @@ -5113,14 +5272,14 @@ class admin_setting_manageeditors extends admin_setting { $updown .= "pix_url('t/up') . "\" alt=\"up\" /> "; } else { - $updown .= "pix_url('spacer.gif') . "\" class=\"icon\" alt=\"\" /> "; + $updown .= "pix_url('spacer') . "\" class=\"icon\" alt=\"\" /> "; } if ($updowncount < $editorcount) { $updown .= ""; $updown .= "pix_url('t/down') . "\" alt=\"down\" />"; } else { - $updown .= "pix_url('spacer.gif') . "\" class=\"icon\" alt=\"\" />"; + $updown .= "pix_url('spacer') . "\" class=\"icon\" alt=\"\" />"; } ++ $updowncount; } @@ -5561,7 +5720,7 @@ function admin_get_root($reload=false, $requirefulltree=true) { $ADMIN->loaded = true; } - + return $ADMIN; } @@ -6217,7 +6376,7 @@ class admin_setting_managerepository extends admin_setting { * Helper function that generates a moodle_url object * relevant to the repository */ - + function repository_action_url($repository) { return new moodle_url('/admin/repository.php', array('sesskey'=>sesskey(), 'repos'=>$repository)); } @@ -6250,7 +6409,7 @@ class admin_setting_managerepository extends admin_setting { // Set strings that are used multiple times $settingsstr = get_string('settings'); $disablestr = get_string('disable'); - + // Table to list plug-ins $table = new html_table(); $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr); @@ -6296,7 +6455,7 @@ class admin_setting_managerepository extends admin_setting { } else { $currentaction = 'hide'; } - + $select = new single_select($this->repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename)); // Display up/down link @@ -7133,4 +7292,4 @@ class admin_setting_configcolourpicker extends admin_setting { return format_admin_setting($this, $this->visiblename, $content, $this->description, false, '', $this->get_defaultsetting(), $query); } -} \ No newline at end of file +} diff --git a/lib/completion/completion_criteria_duration.php b/lib/completion/completion_criteria_duration.php index 43ee857c278..6ad1ba2fb1d 100644 --- a/lib/completion/completion_criteria_duration.php +++ b/lib/completion/completion_criteria_duration.php @@ -171,6 +171,8 @@ class completion_criteria_duration extends completion_criteria { public function cron() { global $DB; +//TODO: MDL-22797 completion needs to be updated to use new enrolment framework + // Get all users who match meet this criteria $sql = ' SELECT DISTINCT diff --git a/lib/completion/cron.php b/lib/completion/cron.php index 29167853f57..9c8b2e8d7d6 100644 --- a/lib/completion/cron.php +++ b/lib/completion/cron.php @@ -53,6 +53,8 @@ function completion_cron() { function completion_cron_mark_started() { global $CFG, $DB; +//TODO: MDL-22797 completion needs to be updated to use new enrolment framework + if (debugging()) { mtrace('Marking users as started'); } diff --git a/lib/datalib.php b/lib/datalib.php index 18ddf5005c7..e8197caee61 100644 --- a/lib/datalib.php +++ b/lib/datalib.php @@ -85,82 +85,6 @@ function get_admins() { return $DB->get_records_sql($sql); } -/** - * Get all of the courses in a given meta course - * - * @global object - * @param int $metacourseid The metacourse id - * @return array - */ -function get_courses_in_metacourse($metacourseid) { - global $DB; - - $sql = "SELECT c.id, c.shortname, c.fullname - FROM {course} c, {course_meta} mc - WHERE mc.parent_course = ? AND mc.child_course = c.id - ORDER BY c.shortname"; - $params = array($metacourseid); - - return $DB->get_records_sql($sql, $params); -} - -/** - * @todo Document this function - * - * @global object - * @uses SITEID - * @param int $metacourseid - * @return array - */ -function get_courses_notin_metacourse($metacourseid) { - global $DB; - - if ($alreadycourses = get_courses_in_metacourse($metacourseid)) { - $alreadycourses = implode(',',array_keys($alreadycourses)); - $alreadycourses = "AND c.id NOT IN ($alreadycourses)"; - } else { - $alreadycourses = ""; - } - - $sql = "SELECT c.id,c.shortname,c.fullname - FROM {course} c - WHERE c.id != ? and c.id != ".SITEID." and c.metacourse != 1 - $alreadycourses - ORDER BY c.shortname"; - $params = array($metacourseid); - - return $DB->get_records_sql($sql, $params); -} - -/** - * @todo Document this function - * - * This function is nearly identical to {@link get_courses_notin_metacourse()} - * - * @global object - * @uses SITEID - * @param int $metacourseid - * @return int The count - */ -function count_courses_notin_metacourse($metacourseid) { - global $DB; - - if ($alreadycourses = get_courses_in_metacourse($metacourseid)) { - $alreadycourses = implode(',',array_keys($alreadycourses)); - $alreadycourses = "AND c.id NOT IN ($alreadycourses)"; - } else { - $alreadycourses = ""; - } - - $sql = "SELECT COUNT(c.id) - FROM {course} c - WHERE c.id != ? and c.id != ".SITEID." and c.metacourse != 1 - $alreadycourses"; - $params = array($metacourseid); - - return $DB->count_records_sql($sql, $params); -} - /** * Search through course users * @@ -606,9 +530,8 @@ function get_courses_wmanagers($categoryid=0, $sort="c.sortorder ASC", $fields=a $basefields = array('id', 'category', 'sortorder', 'shortname', 'fullname', 'idnumber', - 'guest', 'startdate', 'visible', - 'newsitems', 'cost', 'enrol', - 'groupmode', 'groupmodeforce'); + 'startdate', 'visible', + 'newsitems', 'groupmode', 'groupmodeforce'); if (!is_null($fields) && is_string($fields)) { if (empty($fields)) { @@ -670,12 +593,12 @@ function get_courses_wmanagers($categoryid=0, $sort="c.sortorder ASC", $fields=a return array(); // no courses! } - $CFG->coursemanager = trim($CFG->coursemanager); - if (empty($CFG->coursemanager)) { + $CFG->coursecontact = trim($CFG->coursecontact); + if (empty($CFG->coursecontact)) { return $courses; } - $managerroles = split(',', $CFG->coursemanager); + $managerroles = split(',', $CFG->coursecontact); $catctxids = ''; if (count($managerroles)) { if ($allcats === true) { @@ -724,7 +647,7 @@ function get_courses_wmanagers($categoryid=0, $sort="c.sortorder ASC", $fields=a $sql .= " OR ra.contextid IN ($catctxids) )"; } - $sql .= "AND ra.roleid IN ({$CFG->coursemanager}) + $sql .= "AND ra.roleid IN ({$CFG->coursecontact}) $categoryclause ORDER BY r.sortorder ASC, ctx.contextlevel ASC, ra.sortorder ASC"; $rs = $DB->get_recordset_sql($sql, $params); @@ -771,293 +694,6 @@ function get_courses_wmanagers($categoryid=0, $sort="c.sortorder ASC", $fields=a return $courses; } -/** - * Convenience function - lists courses that a user has access to view. - * - * For admins and others with access to "every" course in the system, we should - * try to get courses with explicit RAs. - * - * NOTE: this function is heavily geared towards the perspective of the user - * passed in $userid. So it will hide courses that the user cannot see - * (for any reason) even if called from cron or from another $USER's - * perspective. - * - * If you really want to know what courses are assigned to the user, - * without any hiding or scheming, call the lower-level - * get_user_courses_bycap(). - * - * - * Notes inherited from get_user_courses_bycap(): - * - * - $fields is an array of fieldnames to ADD - * so name the fields you really need, which will - * be added and uniq'd - * - * - the course records have $c->context which is a fully - * valid context object. Saves you a query per course! - * - * @global object - * @global object - * @global object - * @uses CONTEXT_SYSTEM - * @uses CONTEXT_COURSE - * @uses CONTEXT_COURSECAT - * @param int $userid The user of interest - * @param string $sort the sortorder in the course table - * @param array $fields names of _additional_ fields to return (also accepts a string) - * @param bool $doanything True if using the doanything flag - * @param int $limit Maximum number of records to return, or 0 for unlimited - * @return array Array of {@link $COURSE} of course objects - */ -function get_my_courses($userid, $sort='visible DESC,sortorder ASC', $fields=NULL, $doanything=false,$limit=0) { - global $CFG, $USER, $DB; - - // Guest account does not have any courses - if (isguestuser()) { - return(array()); - } - - $basefields = array('id', 'category', 'sortorder', - 'shortname', 'fullname', 'idnumber', - 'guest', 'startdate', 'visible', - 'newsitems', 'cost', 'enrol', - 'groupmode', 'groupmodeforce'); - - if (!is_null($fields) && is_string($fields)) { - if (empty($fields)) { - $fields = $basefields; - } else { - // turn the fields from a string to an array that - // get_user_courses_bycap() will like... - $fields = explode(',',$fields); - $fields = array_map('trim', $fields); - $fields = array_unique(array_merge($basefields, $fields)); - } - } elseif (is_array($fields)) { - $fields = array_unique(array_merge($basefields, $fields)); - } else { - $fields = $basefields; - } - - $orderby = ''; - $sort = trim($sort); - if (!empty($sort)) { - $rawsorts = explode(',', $sort); - $sorts = array(); - foreach ($rawsorts as $rawsort) { - $rawsort = trim($rawsort); - if (strpos($rawsort, 'c.') === 0) { - $rawsort = substr($rawsort, 2); - } - $sorts[] = trim($rawsort); - } - $sort = 'c.'.implode(',c.', $sorts); - $orderby = "ORDER BY $sort"; - } - - // - // Logged-in user - Check cached courses - // - // NOTE! it's a _string_ because - // - it's all we'll ever use - // - it serialises much more compact than an array - // this a big concern here - cost of serialise - // and unserialise gets huge as the session grows - // - // If the courses are too many - it won't be set - // for large numbers of courses, caching in the session - // has marginal benefits (costs too much, not - // worthwhile...) and we may hit SQL parser limits - // because we use IN() - // - if ($userid === $USER->id) { - if (isset($USER->loginascontext) - && $USER->loginascontext->contextlevel == CONTEXT_COURSE) { - // list _only_ this course - // anything else is asking for trouble... - $courseids = $USER->loginascontext->instanceid; - } elseif (isset($USER->mycourses) - && is_string($USER->mycourses)) { - if ($USER->mycourses === '') { - // empty str means: user has no courses - // ... so do the easy thing... - return array(); - } else { - $courseids = $USER->mycourses; - } - } - if (isset($courseids)) { - // The data massaging here MUST be kept in sync with - // get_user_courses_bycap() so we return - // the same... - // (but here we don't need to check has_cap) - $coursefields = 'c.' .join(',c.', $fields); - list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); - $sql = "SELECT $coursefields $ccselect, cc.path AS categorypath - FROM {course} c - JOIN {course_categories} cc ON c.category=cc.id - $ccjoin - WHERE c.id IN ($courseids) - $orderby"; - $rs = $DB->get_recordset_sql($sql); - $courses = array(); - $cc = 0; // keep count - foreach ($rs as $c) { - // build the context obj - context_instance_preload($c); - - if ($limit > 0 && $cc >= $limit) { - break; - } - - $courses[$c->id] = $c; - $cc++; - } - $rs->close(); - return $courses; - } - } - - // Non-cached - get accessinfo - if ($userid === $USER->id && isset($USER->access)) { - $accessinfo = $USER->access; - } else { - $accessinfo = get_user_access_sitewide($userid); - } - - - $courses = get_user_courses_bycap($userid, 'moodle/course:participate', $accessinfo, - $doanything, $sort, $fields, - $limit); - - $cats = NULL; - // If we have to walk category visibility - // to eval course visibility, get the categories - if (empty($CFG->allowvisiblecoursesinhiddencategories)) { - list($ccselect, $ccjoin) = context_instance_preload_sql('cc.id', CONTEXT_COURSECAT, 'ctx'); - $sql = "SELECT cc.id, cc.path, cc.visible $ccselect - FROM {course_categories} cc - $ccjoin - ORDER BY cc.id"; - $rs = $DB->get_recordset_sql($sql); - - // Using a temporary array instead of $cats here, to avoid a "true" result when isnull($cats) further down - $categories = array(); - foreach($rs as $course_cat) { - // build the context obj - context_instance_preload($course_cat); - $categories[$course_cat->id] = $course_cat; - } - $rs->close(); - - if (!empty($categories)) { - $cats = $categories; - } - - unset($course_cat); - } - // - // Strangely, get_my_courses() is expected to return the - // array keyed on id, which messes up the sorting - // So do that, and also cache the ids in the session if appropriate - // - $kcourses = array(); - $courses_count = count($courses); - $cacheids = NULL; - $vcatpaths = array(); - if ($userid === $USER->id && $courses_count < 500) { - $cacheids = array(); - } - for ($n=0; $n<$courses_count; $n++) { - - // - // Check whether $USER (not $userid) can _actually_ see them - // Easy if $CFG->allowvisiblecoursesinhiddencategories - // is set, and we don't have to care about categories. - // Lots of work otherwise... (all in mem though!) - // - $cansee = false; - if (is_null($cats)) { // easy rules! - if ($courses[$n]->visible == true) { - $cansee = true; - } elseif (has_capability('moodle/course:viewhiddencourses', - $courses[$n]->context, $USER->id)) { - $cansee = true; - } - } else { - // - // Is the cat visible? - // we have to assume it _is_ visible - // so we can shortcut when we find a hidden one - // - $viscat = true; - $cpath = $courses[$n]->categorypath; - if (isset($vcatpaths[$cpath])) { - $viscat = $vcatpaths[$cpath]; - } else { - $cpath = substr($cpath,1); // kill leading slash - $cpath = explode('/',$cpath); - $ccct = count($cpath); - for ($m=0;$m<$ccct;$m++) { - $ccid = $cpath[$m]; - if ($cats[$ccid]->visible==false) { - $viscat = false; - break; - } - } - $vcatpaths[$courses[$n]->categorypath] = $viscat; - } - - // - // Perhaps it's actually visible to $USER - // check moodle/category:viewhiddencategories - // - // The name isn't obvious, but the description says - // "See hidden categories" so the user shall see... - // But also check if the allowvisiblecoursesinhiddencategories setting is true, and check for course visibility - if ($viscat === false) { - $catctx = $cats[$courses[$n]->category]->context; - if (has_capability('moodle/category:viewhiddencategories', $catctx, $USER->id)) { - $vcatpaths[$courses[$n]->categorypath] = true; - $viscat = true; - } elseif ($CFG->allowvisiblecoursesinhiddencategories && $courses[$n]->visible == true) { - $viscat = true; - } - } - - // - // Decision matrix - // - if ($viscat === true) { - if ($courses[$n]->visible == true) { - $cansee = true; - } elseif (has_capability('moodle/course:viewhiddencourses', - $courses[$n]->context, $USER->id)) { - $cansee = true; - } - } - } - if ($cansee === true) { - $kcourses[$courses[$n]->id] = $courses[$n]; - if (is_array($cacheids)) { - $cacheids[] = $courses[$n]->id; - } - } - } - if (is_array($cacheids)) { - // Only happens - // - for the logged in user - // - below the threshold (500) - // empty string is _valid_ - $USER->mycourses = join(',',$cacheids); - } elseif ($userid === $USER->id && isset($USER->mycourses)) { - // cheap sanity check - unset($USER->mycourses); - } - - return $kcourses; -} - /** * A list of courses that match a search * @@ -2285,75 +1921,6 @@ function print_object($object) { echo ''; } -/** - * Check whether a course is visible through its parents - * path. - * - * Notes: - * - * - All we need from the course is ->category. _However_ - * if the course object has a categorypath property, - * we'll save a dbquery - * - * - If we return false, you'll still need to check if - * the user can has the 'moodle/category:viewhiddencategories' - * capability... - * - * - Will generate 2 DB calls. - * - * - It does have a small local cache, however... - * - * - Do NOT call this over many courses as it'll generate - * DB traffic. Instead, see what get_my_courses() does. - * - * @global object - * @global object - * @staticvar array $mycache - * @param object $course A course object - * @return bool - */ -function course_parent_visible($course = null) { - global $CFG, $DB; - //return true; - static $mycache; - - if (!is_object($course)) { - return true; - } - if (!empty($CFG->allowvisiblecoursesinhiddencategories)) { - return true; - } - - if (!isset($mycache)) { - $mycache = array(); - } else { - // cast to force assoc array - $k = (string)$course->category; - if (isset($mycache[$k])) { - return $mycache[$k]; - } - } - - if (isset($course->categorypath)) { - $path = $course->categorypath; - } else { - $path = $DB->get_field('course_categories', 'path', array('id'=>$course->category)); - } - $catids = substr($path,1); // strip leading slash - $catids = str_replace('/',',',$catids); - - $sql = "SELECT MIN(visible) - FROM {course_categories} - WHERE id IN ($catids)"; - $vis = $DB->get_field_sql($sql); - - // cast to force assoc array - $k = (string)$course->category; - $mycache[$k] = $vis; - - return $vis; -} - /** * This function is the official hook inside XMLDB stuff to delegate its debug to one * external function. diff --git a/lib/db/access.php b/lib/db/access.php index e1f520aab28..8ca61bb328e 100644 --- a/lib/db/access.php +++ b/lib/db/access.php @@ -596,19 +596,6 @@ $capabilities = array( ) ), - 'moodle/role:unassignself' => array( - - 'captype' => 'write', - 'contextlevel' => CONTEXT_COURSE, - 'archetypes' => array( - 'student' => (empty($CFG->allowunenrol)) ? CAP_INHERIT : CAP_ALLOW, - 'teacher' => CAP_ALLOW, - 'editingteacher' => CAP_ALLOW, - 'coursecreator' => CAP_ALLOW, - 'manager' => CAP_ALLOW - ) - ), - 'moodle/role:switchroles' => array( 'riskbitmask' => RISK_XSS | RISK_PERSONAL, @@ -725,20 +712,6 @@ $capabilities = array( ) ), - /* originally this capability was called moodle/course:view, - * but since 2.0 it is used for access to course without the enrolment - */ - 'moodle/course:participate' => array( - - 'captype' => 'read', - 'contextlevel' => CONTEXT_COURSE, - 'archetypes' => array( - 'student' => CAP_ALLOW, - 'teacher' => CAP_ALLOW, - 'editingteacher' => CAP_ALLOW - ) - ), - 'moodle/course:view' => array( 'captype' => 'read', @@ -748,6 +721,32 @@ $capabilities = array( ) ), + /* review course enrolments - no group restrictions, it is really full access to all participants info*/ + 'moodle/course:enrolreview' => array( + + 'riskbitmask' => RISK_PERSONAL, + + 'captype' => 'read', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + ) + ), + + /* add, remove, hide enrol instances in courses */ + 'moodle/course:enrolconfig' => array( + + 'riskbitmask' => RISK_PERSONAL, + + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + ) + ), + 'moodle/course:bulkmessaging' => array( 'riskbitmask' => RISK_SPAM, @@ -791,6 +790,7 @@ $capabilities = array( 'captype' => 'write', 'contextlevel' => CONTEXT_COURSE, 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, 'manager' => CAP_ALLOW ) ), @@ -819,18 +819,6 @@ $capabilities = array( ) ), - 'moodle/course:managemetacourse' => array( - - 'riskbitmask' => RISK_XSS | RISK_PERSONAL, - - 'captype' => 'write', - 'contextlevel' => CONTEXT_COURSE, - 'archetypes' => array( - 'editingteacher' => CAP_ALLOW, - 'manager' => CAP_ALLOW - ) - ), - 'moodle/course:activityvisibility' => array( 'captype' => 'write', diff --git a/lib/db/events.php b/lib/db/events.php index 39079774974..6ba651876ed 100644 --- a/lib/db/events.php +++ b/lib/db/events.php @@ -13,7 +13,7 @@ // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // -// the Free Software Foundation; either version 2 of the License, or // +// the Free Software Foundation; either version 3 of the License, or // // (at your option) any later version. // // // // This program is distributed in the hope that it will be useful, // @@ -29,13 +29,15 @@ /* List of handlers */ -$handlers = array ( +$handlers = array( /* * portfolio queued event - for non interactive file transfers - * NOTE: this is a hack, please do not add any more things like this here - * (it is just abusing cron to do very time consuming things which is wrong) -*/ + * NOTE: this is a HACK, please do not add any more things like this here + * (it is just abusing cron to do very time consuming things which is wrong any way) + * + * TODO: this has to be moved into separate queueing framework.... + */ 'portfolio_send' => array ( 'handlerfile' => '/lib/portfolio.php', 'handlerfunction' => 'portfolio_handle_event', // argument to call_user_func(), could be an array @@ -43,7 +45,7 @@ $handlers = array ( ), -/* more go here */ +/* no more here please, core should not consume any events!!!!!!! */ ); @@ -68,6 +70,20 @@ course_updated - object course table record course_content_removed - object course table record course_deleted - object course table record +user_enrolled - object record from user_enrolments table + courseid,enrol +user_unenrol_modified - object record from user_enrolments table + courseid,enrol +user_unenrolled - object record from user_enrolments table + courseid,enrol,lastenrol + +==== cohort related events === + + +cohort_added - object cohort table record +cohort_updated - object cohort table record +cohort_deleted - object cohort table record + +cohort_member_added - object cohortid, userid properties +cohort_member_removed - object cohortid, userid properties + ==== group related events ==== groups_group_created - object groups_group table record @@ -97,8 +113,4 @@ modulename_mod_deleted - int courseid, int cmid - happens when a module is delet modulename_mod_created - int courseid, int cmid - happens when a module is created -eg quiz_mod_created modulename_mod_updated - int courseid, int cmid - happens when a module is updated -eg quiz_mod_updated -==== Assignment Related events ==== - -assignment_finalize_sent - object course, object user, object cm, object assignment, fileareaname -assignment_file_sent - object course, object user, object cm, object assignment, object file */ diff --git a/lib/db/install.php b/lib/db/install.php index e7eba9a2459..0415eae1544 100644 --- a/lib/db/install.php +++ b/lib/db/install.php @@ -45,8 +45,7 @@ function xmldb_main_install() { 'rolesactive' => '0', // marks fully set up system 'auth' => 'email', 'auth_pop3mailbox' => 'INBOX', - 'enrol' => 'manual', - 'enrol_plugins_enabled' => 'manual', + 'enrol_plugins_enabled' => 'manual,guest,self,cohort', 'style' => 'default', 'template' => 'default', 'theme' => theme_config::DEFAULT_THEME, @@ -126,8 +125,8 @@ function xmldb_main_install() { update_log_display_entry('course', 'user report', 'user', 'CONCAT(firstname,\' \',lastname)'); update_log_display_entry('course', 'view', 'course', 'fullname'); update_log_display_entry('course', 'update', 'course', 'fullname'); - update_log_display_entry('course', 'enrol', 'course', 'fullname'); - update_log_display_entry('course', 'unenrol', 'course', 'fullname'); + update_log_display_entry('course', 'enrol', 'user', 'course', 'fullname'); // there should be some way to store user id of the enrolled user! + update_log_display_entry('course', 'unenrol', 'user', 'course', 'fullname'); // there should be some way to store user id of the enrolled user! update_log_display_entry('course', 'report log', 'course', 'fullname'); update_log_display_entry('course', 'report live', 'course', 'fullname'); update_log_display_entry('course', 'report outline', 'course', 'fullname'); diff --git a/lib/db/install.xml b/lib/db/install.xml index b807afea341..e115725e07c 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -1,5 +1,5 @@ - @@ -70,9 +70,8 @@ - - - + + @@ -80,38 +79,26 @@ - - - - - + + + - - + + + - - - - - - - - - - - - - - - - - + + + + + + @@ -133,8 +120,9 @@ - - + + + @@ -237,7 +225,7 @@
- +
@@ -251,21 +239,67 @@
- +
- - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - +
- +
+ + + + + + + + + + + + + + + + + + + +
+ @@ -1066,19 +1100,17 @@
- +
- - - - - - - - + + + + + + @@ -1087,8 +1119,7 @@ - - +
@@ -2013,7 +2044,7 @@ - + @@ -2291,7 +2322,7 @@
- +
@@ -2302,7 +2333,35 @@
- +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ diff --git a/lib/db/services.php b/lib/db/services.php index 24673f29ea9..cd591f32c22 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -131,19 +131,28 @@ $functions = array( 'type' => 'write', ), - 'moodle_enrol_role_assign' => array( + 'moodle_enrol_get_enrolled_users' => array( + 'classname' => 'moodle_enrol_external', + 'methodname' => 'get_enrolled_users', + 'classpath' => 'enrol/externallib.php', + 'description' => 'Get list of course participants', + 'type' => 'read', + ), + + 'moodle_role_assign' => array( 'classname' => 'moodle_enrol_external', 'methodname' => 'role_assign', 'classpath' => 'enrol/externallib.php', - 'description' => 'Enrol users.', + 'description' => 'Manual role assignments.', 'type' => 'write', ), - 'moodle_enrol_role_unassign' => array( + 'moodle_role_unassign' => array( 'classname' => 'moodle_enrol_external', 'methodname' => 'role_unassign', 'classpath' => 'enrol/externallib.php', - 'description' => 'Unenrol users.', + 'description' => 'Manual role unassignments.', 'type' => 'write', ), + ); diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 34e46505c8a..2d073d78b96 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -897,78 +897,6 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint($result, 2008101300); } - /// New table for storing which roles can be assigned in which contexts. - if ($result && $oldversion < 2008110601) { - - /// Define table role_context_levels to be created - $table = new xmldb_table('role_context_levels'); - - /// Adding fields to table role_context_levels - $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); - $table->add_field('roleid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); - $table->add_field('contextlevel', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); - - /// Adding keys to table role_context_levels - $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); - $table->add_key('contextlevel-roleid', XMLDB_KEY_UNIQUE, array('contextlevel', 'roleid')); - $table->add_key('roleid', XMLDB_KEY_FOREIGN, array('roleid'), 'role', array('id')); - - /// Conditionally launch create table for role_context_levels - if (!$dbman->table_exists($table)) { - $dbman->create_table($table); - } - - /// Main savepoint reached - upgrade_main_savepoint($result, 2008110601); - } - - /// Now populate the role_context_levels table with the defaults that match - /// moodle_install_roles, and any other combinations that exist in this system. - if ($result && $oldversion < 2008110602) { - $roleids = $DB->get_records_menu('role', array(), '', 'shortname,id'); - - /// Defaults, should match moodle_install_roles. - $rolecontextlevels = array(); - if (isset($roleids['coursecreator'])) { - $rolecontextlevels[$roleids['coursecreator']] = get_default_contextlevels('coursecreator'); - } - if (isset($roleids['editingteacher'])) { - $rolecontextlevels[$roleids['editingteacher']] = get_default_contextlevels('editingteacher'); - } - if (isset($roleids['teacher'])) { - $rolecontextlevels[$roleids['teacher']] = get_default_contextlevels('teacher'); - } - if (isset($roleids['student'])) { - $rolecontextlevels[$roleids['student']] = get_default_contextlevels('student'); - } - if (isset($roleids['guest'])) { - $rolecontextlevels[$roleids['guest']] = get_default_contextlevels('guest'); - } - if (isset($roleids['user'])) { - $rolecontextlevels[$roleids['user']] = get_default_contextlevels('user'); - } - - /// See what other role assignments are in this database, extend the allowed - /// lists to allow them too. - $existingrolecontextlevels = $DB->get_recordset_sql('SELECT DISTINCT ra.roleid, con.contextlevel FROM - {role_assignments} ra JOIN {context} con ON ra.contextid = con.id'); - foreach ($existingrolecontextlevels as $rcl) { - if (!isset($rolecontextlevels[$rcl->roleid])) { - $rolecontextlevels[$rcl->roleid] = array($rcl->contextlevel); - } else if (!in_array($rcl->contextlevel, $rolecontextlevels[$rcl->roleid])) { - $rolecontextlevels[$rcl->roleid][] = $rcl->contextlevel; - } - } - - /// Put the data into the database. - foreach ($rolecontextlevels as $roleid => $contextlevels) { - set_role_contextlevels($roleid, $contextlevels); - } - - /// Main savepoint reached - upgrade_main_savepoint($result, 2008110602); - } - /// Drop the deprecated teacher, teachers, student and students columns from the course table. if ($result && $oldversion < 2008111200) { $table = new xmldb_table('course'); @@ -1129,14 +1057,6 @@ function xmldb_main_upgrade($oldversion) { require_once($CFG->dirroot . '/course/lib.php'); rebuild_course_cache(0, true); - /// For developer upgrades, turn on the conditional activities and completion - /// features automatically (to gain more testing) -//TODO: remove before 2.0 final! - if (debugging('', DEBUG_DEVELOPER)) { - set_config('enableavailability', 1); - set_config('enablecompletion', 1); - } - /// Main savepoint reached upgrade_main_savepoint($result, 2008121701); } @@ -3304,14 +3224,6 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL"); $DB->delete_records('role_capabilities', array('capability'=>'moodle/site:config', 'roleid'=>$manager->id)); // only site admins may configure servers // note: doanything and legacy caps are deleted automatically, they get moodle/course:view later at the end of the upgrade - // set usable contexts - $DB->delete_records('role_context_levels', array('roleid'=>$manager->id)); - $assignlevels = array(CONTEXT_SYSTEM, CONTEXT_COURSECAT, CONTEXT_COURSE); - foreach ($assignlevels as $assignlevel) { - $record = (object)array('roleid'=>$manager->id, 'contextlevel'=>$assignlevel); - $DB->insert_record('role_context_levels', $record); - } - // remove manager role assignments bellow the course context level - admin role was never intended for activities and blocks, // the problem is that those assignments would not be visible after upgrade and old style admins in activities make no sense anyway $DB->delete_records_select('role_assignments', "roleid = :manager AND contextid IN (SELECT id FROM {context} WHERE contextlevel > 50)", array('manager'=>$manager->id)); @@ -3385,33 +3297,99 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL"); unset_config('guestroleid'); } } else { - upgrade_log(UPGRADE_LOG_NOTICE, null, 'Role specified in Default guest role (guestroleid) doeas not exist, setting cleared.'); + upgrade_log(UPGRADE_LOG_NOTICE, null, 'Role specified in Default guest role (guestroleid) does not exist, setting cleared.'); unset_config('guestroleid'); } } // remove all roles of the guest account - the only way to change it is to override the guest role, sorry - // the guest account gets all the role assignemnts on the fly whcih works fine in has_capability(), + // the guest account gets all the role assignments on the fly which works fine in has_capability(), $DB->delete_records_select('role_assignments', "userid IN (SELECT id FROM {user} WHERE username = 'guest')"); upgrade_main_savepoint($result, 2010033102.08); } + /// New table for storing which roles can be assigned in which contexts. if ($result && $oldversion < 2010033102.09) { - // For MDL-17501. Ensure that any role that has moodle/course:update also has moodle/course:visibility. - // Get the roles with 'moodle/course:update'. - $systemcontext = get_context_instance(CONTEXT_SYSTEM); - $roles = get_roles_with_capability('moodle/course:update', CAP_ALLOW, $systemcontext); - // Give those roles 'moodle/course:visibility'. - foreach ($roles as $role) { - assign_capability('moodle/course:visibility', CAP_ALLOW, $role->id, $systemcontext->id); + /// Define table role_context_levels to be created + $table = new xmldb_table('role_context_levels'); + + /// Adding fields to table role_context_levels + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); + $table->add_field('roleid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); + $table->add_field('contextlevel', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); + + /// Adding keys to table role_context_levels + $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); + $table->add_key('contextlevel-roleid', XMLDB_KEY_UNIQUE, array('contextlevel', 'roleid')); + $table->add_key('roleid', XMLDB_KEY_FOREIGN, array('roleid'), 'role', array('id')); + + /// Conditionally launch create table for role_context_levels + if (!$dbman->table_exists($table)) { + $dbman->create_table($table); } - // Force all sessions to refresh access data. - mark_context_dirty($systemcontext->path); + /// Main savepoint reached + upgrade_main_savepoint($result, 2010033102.09); + } + + if ($result && $oldversion < 2010033102.10) { + // Now populate the role_context_levels table with the default values + // NOTE: do not use accesslib methods here + + $rolecontextlevels = array(); + $defaults = array('manager' => array(CONTEXT_SYSTEM, CONTEXT_COURSECAT, CONTEXT_COURSE), + 'coursecreator' => array(CONTEXT_SYSTEM, CONTEXT_COURSECAT), + 'editingteacher' => array(CONTEXT_COURSE, CONTEXT_MODULE), + 'teacher' => array(CONTEXT_COURSE, CONTEXT_MODULE), + 'student' => array(CONTEXT_COURSE, CONTEXT_MODULE), + 'guest' => array(), + 'user' => array(), + 'frontpage' => array()); + + $roles = $DB->get_records('role', array(), '', 'id, archetype'); + foreach ($roles as $role) { + if (isset($defaults[$role->archetype])) { + $rolecontextlevels[$role->id] = $defaults[$role->archetype]; + } + } + + // add roles without archetypes, it may contain weird things, but we can not fix them + $sql = "SELECT DISTINCT ra.roleid, con.contextlevel + FROM {role_assignments} ra + JOIN {context} con ON ra.contextid = con.id"; + $existingrolecontextlevels = $DB->get_recordset_sql($sql); + foreach ($existingrolecontextlevels as $rcl) { + if (isset($roleids[$rcl->roleid])) { + continue; + } + if (!isset($rolecontextlevels[$rcl->roleid])) { + $rolecontextlevels[$rcl->roleid] = array($rcl->contextlevel); + } else if (!in_array($rcl->contextlevel, $rolecontextlevels[$rcl->roleid])) { + $rolecontextlevels[$rcl->roleid][] = $rcl->contextlevel; + } + } + $existingrolecontextlevels->close(); + + // Put the data into the database. + $rcl = new object(); + foreach ($rolecontextlevels as $roleid => $contextlevels) { + $rcl->roleid = $roleid; + foreach ($contextlevels as $level) { + $rcl->contextlevel = $level; + $DB->insert_record('role_context_levels', $rcl, false); + } + } + + // release memory!! + unset($roles); + unset($defaults); + unset($rcl); + unset($existingrolecontextlevels); + unset($rolecontextlevels); // Main savepoint reached - upgrade_main_savepoint($result, 2010033102.09); + upgrade_main_savepoint($result, 2010033102.10); } if ($result && $oldversion < 2010040700) { @@ -3564,7 +3542,7 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL"); $table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null); $table->add_field('description', XMLDB_TYPE_TEXT, 'small', null, null, null, null); $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); - $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null); + $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null); $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); @@ -4117,8 +4095,7 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL"); upgrade_main_savepoint($result, 2010052200); } - - if ($result && $oldversion < 2010052401) { + if ($result && $oldversion < 2010052401) { /// Define field status to be added to course_published $table = new xmldb_table('course_published'); @@ -4178,11 +4155,668 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL"); /// Main savepoint reached upgrade_main_savepoint($result, 2010052801); } + + if ($result && $oldversion < 2010061900.01) { + // Define table enrol to be created + $table = new xmldb_table('enrol'); + + // Adding fields to table enrol + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); + $table->add_field('enrol', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null); + $table->add_field('status', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); + $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); + $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); + $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null); + $table->add_field('enrolperiod', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, '0'); + $table->add_field('enrolstartdate', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, '0'); + $table->add_field('enrolenddate', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, '0'); + $table->add_field('expirynotify', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, null, null, '0'); + $table->add_field('expirythreshold', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, '0'); + $table->add_field('notifyall', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, null, null, '0'); + $table->add_field('password', XMLDB_TYPE_CHAR, '50', null, null, null, null); + $table->add_field('cost', XMLDB_TYPE_CHAR, '20', null, null, null, null); + $table->add_field('currency', XMLDB_TYPE_CHAR, '3', null, null, null, null); + $table->add_field('roleid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, '0'); + $table->add_field('customint1', XMLDB_TYPE_INTEGER, '10', null, null, null, null); + $table->add_field('customint2', XMLDB_TYPE_INTEGER, '10', null, null, null, null); + $table->add_field('customint3', XMLDB_TYPE_INTEGER, '10', null, null, null, null); + $table->add_field('customint4', XMLDB_TYPE_INTEGER, '10', null, null, null, null); + $table->add_field('customchar1', XMLDB_TYPE_CHAR, '255', null, null, null, null); + $table->add_field('customchar2', XMLDB_TYPE_CHAR, '255', null, null, null, null); + $table->add_field('customdec1', XMLDB_TYPE_NUMBER, '12, 7', null, null, null, null); + $table->add_field('customdec2', XMLDB_TYPE_NUMBER, '12, 7', null, null, null, null); + $table->add_field('customtext1', XMLDB_TYPE_TEXT, 'big', null, null, null, null); + $table->add_field('customtext2', XMLDB_TYPE_TEXT, 'big', null, null, null, null); + $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); + $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); + + // Adding keys to table enrol + $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); + $table->add_key('courseid', XMLDB_KEY_FOREIGN, array('courseid'), 'course', array('id')); + + // Adding indexes to table enrol + $table->add_index('enrol', XMLDB_INDEX_NOTUNIQUE, array('enrol')); + + // launch create table for enrol + $dbman->create_table($table); + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.01); + } + + if ($result && $oldversion < 2010061900.02) { + // Define table course_participant to be created + $table = new xmldb_table('user_enrolments'); + + // Adding fields to table course_participant + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); + $table->add_field('status', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); + $table->add_field('enrolid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); + $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); + $table->add_field('timestart', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); + $table->add_field('timeend', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '2147483647'); + $table->add_field('modifierid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); + $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); + + // Adding keys to table course_participant + $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); + $table->add_key('enrolid', XMLDB_KEY_FOREIGN, array('enrolid'), 'enrol', array('id')); + $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id')); + $table->add_key('modifierid', XMLDB_KEY_FOREIGN, array('modifierid'), 'user', array('id')); + + + // Adding indexes to table user_enrolments + $table->add_index('enrolid-userid', XMLDB_INDEX_UNIQUE, array('enrolid', 'userid')); + + // Launch create table for course_participant + $dbman->create_table($table); + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.02); + } + + if ($result && $oldversion < 2010061900.03) { + // Define field itemid to be added to role_assignments + $table = new xmldb_table('role_assignments'); + $field = new xmldb_field('itemid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, 0, 'enrol'); + + // Launch add field itemid + $dbman->add_field($table, $field); + + // The new enrol plugins may assign one role several times in one context, + // if we did not allow it we would have big problems with roles when unenrolling + $table = new xmldb_table('role_assignments'); + $index = new xmldb_index('contextid-roleid-userid', XMLDB_INDEX_UNIQUE, array('contextid', 'roleid', 'userid')); + + // Conditionally launch drop index contextid-roleid-userid + if ($dbman->index_exists($table, $index)) { + $dbman->drop_index($table, $index); + } + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.03); + } + + if ($result && $oldversion < 2010061900.04) { + // there is no default course role any more, each enrol plugin has to handle it separately + if (!empty($CFG->defaultcourseroleid)) { + $sql = "UPDATE {course} SET defaultrole = :default WHERE defaultrole = 0"; + $params = array('default' => $CFG->defaultcourseroleid); + $DB->execute($sql, $params); + } + unset_config('defaultcourseroleid'); + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.04); + } + + if ($result && $oldversion < 2010061900.05) { + // make sure enrol settings make actually sense and tweak defaults a bit + + $sqlempty = $DB->sql_empty(); + + // set course->enrol to default value so that other upgrade code is simpler + $defaultenrol = empty($CFG->enrol) ? 'manual' : $CFG->enrol; + $sql = "UPDATE {course} SET enrol = ? WHERE enrol = '$sqlempty'"; + $DB->execute($sql, array($defaultenrol)); + unset_config('enrol'); + + if (!isset($CFG->enrol_plugins_enabled) or empty($CFG->enrol_plugins_enabled)) { + set_config('enrol_plugins_enabled', 'manual'); + } else { + $enabledplugins = explode(',', $CFG->enrol_plugins_enabled); + $enabledplugins = array_unique($enabledplugins); + set_config('enrol_plugins_enabled', implode(',', $enabledplugins)); + } + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.05); + } + + if ($result && $oldversion < 2010061900.06) { + $sqlempty = $DB->sql_empty(); + $params = array('siteid'=>SITEID); + + // enable manual in all courses + $sql = "INSERT INTO {enrol} (enrol, status, courseid, sortorder, enrolperiod, expirynotify, expirythreshold, notifyall, roleid, timecreated, timemodified) + SELECT 'manual', 0, id, 0, enrolperiod, expirynotify, expirythreshold, notifystudents, defaultrole, timecreated, timemodified + FROM {course} + WHERE id <> :siteid"; + $DB->execute($sql, $params); + + // enable self enrol only when course enrollable + $sql = "INSERT INTO {enrol} (enrol, status, courseid, sortorder, enrolperiod, enrolstartdate, enrolenddate, expirynotify, expirythreshold, + notifyall, password, roleid, timecreated, timemodified) + SELECT 'self', 0, id, 1, enrolperiod, enrolstartdate, enrolenddate, expirynotify, expirythreshold, + notifystudents, password, defaultrole, timecreated, timemodified + FROM {course} + WHERE enrollable = 1 AND id <> :siteid"; + $DB->execute($sql, $params); + + // enable guest access if previously allowed - separately with or without password + $sql = "INSERT INTO {enrol} (enrol, status, courseid, sortorder, timecreated, timemodified) + SELECT 'guest', 0, id, 2, timecreated, timemodified + FROM {course} + WHERE guest = 1 AND id <> :siteid"; + $DB->execute($sql, $params); + $sql = "INSERT INTO {enrol} (enrol, status, courseid, sortorder, password, timecreated, timemodified) + SELECT 'guest', 0, id, 2, password, timecreated, timemodified + FROM {course} + WHERE guest = 2 and password <> '$sqlempty' AND id <> :siteid"; + $DB->execute($sql, $params); + + upgrade_main_savepoint($result, 2010061900.06); + } + + if ($result && $oldversion < 2010061900.07) { + // now migrate old style "interactive" enrol plugins - we know them by looking into course.enrol + $params = array('siteid'=>SITEID); + $enabledplugins = explode(',', $CFG->enrol_plugins_enabled); + $usedplugins = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {course}"); + foreach ($usedplugins as $plugin) { + if ($plugin === 'manual') { + continue; + } + $enabled = in_array($plugin, $enabledplugins) ? 0 : 1; // 0 means active, 1 disabled + $sql = "INSERT INTO {enrol} (enrol, status, courseid, sortorder, enrolperiod, enrolstartdate, enrolenddate, expirynotify, expirythreshold, + notifyall, password, cost, currency, roleid, timecreated, timemodified) + SELECT enrol, $enabled, id, 4, enrolperiod, enrolstartdate, enrolenddate, expirynotify, expirythreshold, + notifystudents, password, cost, currency, defaultrole, timecreated, timemodified + FROM {course} + WHERE enrol = :plugin AND id <> :siteid"; + $params['plugin'] = $plugin; + $DB->execute($sql, $params); + } + upgrade_main_savepoint($result, 2010061900.07); + } + + if ($result && $oldversion < 2010061900.08) { + // now migrate the rest - these plugins are not in course.enrol, instead we just look for suspicious role assignments, + // unfortunately old enrol plugins were doing sometimes weird role assignments :-( + + // enabled + $processed = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {enrol}"); + $enabledplugins = explode(',', $CFG->enrol_plugins_enabled); + list($sqlnotprocessed, $params) = $DB->get_in_or_equal($processed, SQL_PARAMS_NAMED, 'np00', false); + list($sqlenabled, $params2) = $DB->get_in_or_equal($enabledplugins, SQL_PARAMS_NAMED, 'ena00'); + $params = array_merge($params, $params2); + $params['siteid'] = SITEID; + $sql = "INSERT INTO {enrol} (enrol, status, courseid, sortorder, enrolperiod, enrolstartdate, enrolenddate, expirynotify, expirythreshold, + notifyall, password, cost, currency, roleid, timecreated, timemodified) + SELECT DISTINCT ra.enrol, 0, c.id, 5, c.enrolperiod, c.enrolstartdate, c.enrolenddate, c.expirynotify, c.expirythreshold, + c.notifystudents, c.password, c.cost, c.currency, c.defaultrole, c.timecreated, c.timemodified + FROM {course} c + JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = 50) + JOIN {role_assignments} ra ON (ra.contextid = ctx.id) + WHERE c.id <> :siteid AND ra.enrol $sqlnotprocessed AND ra.enrol $sqlenabled"; + $DB->execute($sql, $params); + + // disabled + $processed = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {enrol}"); + list($sqlnotprocessed, $params) = $DB->get_in_or_equal($processed, SQL_PARAMS_NAMED, 'np00', false); + $params = array_merge($params, $params2); + $params['siteid'] = SITEID; + $sql = "INSERT INTO {enrol} (enrol, status, courseid, sortorder, enrolperiod, enrolstartdate, enrolenddate, expirynotify, expirythreshold, + notifyall, password, cost, currency, roleid, timecreated, timemodified) + SELECT DISTINCT ra.enrol, 1, c.id, 5, c.enrolperiod, c.enrolstartdate, c.enrolenddate, c.expirynotify, c.expirythreshold, + c.notifystudents, c.password, c.cost, c.currency, c.defaultrole, c.timecreated, c.timemodified + FROM {course} c + JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = 50) + JOIN {role_assignments} ra ON (ra.contextid = ctx.id) + WHERE c.id <> :siteid AND ra.enrol $sqlnotprocessed"; + $DB->execute($sql, $params); + + upgrade_main_savepoint($result, 2010061900.08); + } + + if ($result && $oldversion < 2010061900.09) { + // unfortunately there may be still some leftovers + // after reconfigured, uninstalled or borked enrol plugins, + // unfortunately this may be a bit slow - but there should not be many of these + $sqlempty = $DB->sql_empty(); + $sql = "SELECT DISTINCT c.id AS courseid, ra.enrol, e.timecreated, c.timemodified + FROM {course} c + JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = 50) + JOIN {role_assignments} ra ON (ra.contextid = ctx.id AND ra.enrol <> '$sqlempty') + LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = ra.enrol) + WHERE c.id <> :siteid AND e.id IS NULL"; + $params = array('siteid'=>SITEID); + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $enrol) { + $enrol->status = 1; // better disable them + $DB->inert_record('enrol', $enrol); + } + $rs->close(); + upgrade_main_savepoint($result, 2010061900.09); + } + + if ($result && $oldversion < 2010061900.10) { + // migrate existing setup of meta courses + $sql = "INSERT INTO {enrol} (enrol, status, courseid, sortorder, customint1) + SELECT 'meta', 0, parent_course, 5, child_course + FROM {course_meta}"; + $DB->execute($sql); + + upgrade_main_savepoint($result, 2010061900.10); + } + + if ($result && $oldversion < 2010061900.11) { + // nuke any old role assignments+enrolments in previous meta courses, we have to start from scratch + $select = "SELECT ctx.id + FROM {context} ctx + JOIN {course} c ON (c.id = ctx.instanceid AND ctx.contextlevel = 50 AND c.metacourse = 1)"; + $DB->delete_records_select('role_assignments', "contextid IN ($select) AND enrol = 'manual'"); + + // course_meta to be dropped - we use enrol_meta plugin instead now + $table = new xmldb_table('course_meta'); + + // Launch drop table for course_meta + $dbman->drop_table($table); + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.11); + } + + if ($result && $oldversion < 2010061900.12) { + // finally remove all obsolete fields from the course table - yay! + // all the information was migrated to the enrol table + + // Define field guest to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('guest'); + + // Conditionally launch drop field guest + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field password to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('password'); + + // Conditionally launch drop field password + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field enrolperiod to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('enrolperiod'); + + // Conditionally launch drop field enrolperiod + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field cost to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('cost'); + + // Conditionally launch drop field cost + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field currency to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('currency'); + + // Conditionally launch drop field currency + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field metacourse to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('metacourse'); + + // Conditionally launch drop field metacourse + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field expirynotify to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('expirynotify'); + + // Conditionally launch drop field expirynotify + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field expirythreshold to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('expirythreshold'); + + // Conditionally launch drop field expirythreshold + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field notifystudents to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('notifystudents'); + + // Conditionally launch drop field notifystudents + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field enrollable to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('enrollable'); + + // Conditionally launch drop field enrollable + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field enrolstartdate to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('enrolstartdate'); + + // Conditionally launch drop field enrolstartdate + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field enrolenddate to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('enrolenddate'); + + // Conditionally launch drop field enrolenddate + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field enrol to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('enrol'); + + // Conditionally launch drop field enrol + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field defaultrole to be dropped from course + $table = new xmldb_table('course'); + $field = new xmldb_field('defaultrole'); + + // Conditionally launch drop field defaultrole + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + upgrade_main_savepoint($result, 2010061900.12); + } + + if ($result && $oldversion < 2010061900.13) { + // Define field visibleold to be added to course_categories + $table = new xmldb_table('course_categories'); + $field = new xmldb_field('visibleold', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'visible'); + + // Launch add field visibleold + $dbman->add_field($table, $field); + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.13); + } + + if ($result && $oldversion < 2010061900.14) { + // keep previous visible state + $DB->execute("UPDATE {course_categories} SET visibleold = visible"); + + // make sure all subcategories of hidden categories are hidden too, do not rely on category path yet + $sql = "SELECT c.id + FROM {course_categories} c + JOIN {course_categories} pc ON (pc.id = c.parent AND pc.visible = 0) + WHERE c.visible = 1"; + while ($categories = $DB->get_records_sql($sql)) { + foreach ($categories as $cat) { + $DB->set_field('course_categories', 'visible', 0, array('id'=>$cat->id)); + } + } + upgrade_main_savepoint($result, 2010061900.14); + } + + if ($result && $oldversion < 2010061900.15) { + // Define field visibleold to be added to course + $table = new xmldb_table('course'); + $field = new xmldb_field('visibleold', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '1', 'visible'); + + // Launch add field visibleold + $dbman->add_field($table, $field); + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.15); + } + + if ($result && $oldversion < 2010061900.16) { + // keep previous visible state + $DB->execute("UPDATE {course} SET visibleold = visible"); + + // make sure all courses in hidden categories are hidden + $DB->execute("UPDATE {course} SET visible = 0 WHERE category IN (SELECT id FROM {course_categories} WHERE visible = 0)"); + + upgrade_main_savepoint($result, 2010061900.16); + } + + if ($result && $oldversion < 2010061900.20) { + // now set up the enrolments - look for roles with course:participate only at course context - the category enrolments are synchronised later by archetype and new capability + + $syscontext = get_context_instance(CONTEXT_SYSTEM); + $params = array('syscontext'=>$syscontext->id, 'participate'=>'moodle/course:participate'); + $roles = $DB->get_fieldset_sql("SELECT DISTINCT roleid FROM {role_capabilities} WHERE contextid = :syscontext AND capability = :participate AND permission = 1", $params); + list($sqlroles, $params) = $DB->get_in_or_equal($roles, SQL_PARAMS_NAMED, 'r00'); + + $sql = "INSERT INTO {user_enrolments} (status, enrolid, userid, timestart, timeend, modifierid, timemodified) + + SELECT 0, e.id, ra.userid, MIN(ra.timestart), MIN(ra.timeend), 0, MAX(ra.timemodified) + FROM {role_assignments} ra + JOIN {context} c ON (c.id = ra.contextid AND c.contextlevel = 50) + JOIN {enrol} e ON (e.enrol = ra.enrol AND e.courseid = c.instanceid) + JOIN {user} u ON u.id = ra.userid + WHERE u.deleted = 0 AND ra.roleid $sqlroles + GROUP BY e.id, ra.userid"; + $DB->execute($sql, $params); + + upgrade_main_savepoint($result, 2010061900.20); + } + + if ($result && $oldversion < 2010061900.21) { + // hidden is completely removed, timestart+timeend are now in the user_enrolments table + + // Define field hidden to be dropped from role_assignments + $table = new xmldb_table('role_assignments'); + $field = new xmldb_field('hidden'); + + // Conditionally launch drop field hidden + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field timestart to be dropped from role_assignments + $table = new xmldb_table('role_assignments'); + $field = new xmldb_field('timestart'); + + // Conditionally launch drop field timestart + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Define field timeend to be dropped from role_assignments + $table = new xmldb_table('role_assignments'); + $field = new xmldb_field('timeend'); + + // Conditionally launch drop field timeend + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.21); + } + + if ($result && $oldversion < 2010061900.22) { + // Rename field enrol on table role_assignments to component and update content + + $table = new xmldb_table('role_assignments'); + $field = new xmldb_field('enrol', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, 'modifierid'); + + // Launch rename field enrol + $dbman->rename_field($table, $field, 'component'); + + // Changing precision of field component on table role_assignments to (100) + $table = new xmldb_table('role_assignments'); + $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'modifierid'); + + // Launch change of precision for field component + $dbman->change_field_precision($table, $field); + + // Manual is a special case - we use empty string instead now + $params = array('empty'=>$DB->sql_empty(), 'manual'=>'manual'); + $sql = "UPDATE {role_assignments} + SET component = :empty + WHERE component = :manual"; + $DB->execute($sql, $params); + + // Now migrate to real enrol component names + $params = array('empty'=>$DB->sql_empty()); + $concat = $DB->sql_concat("'enrol_'", 'component'); + $sql = "UPDATE {role_assignments} + SET component = $concat + WHERE component <> :empty + AND contextid IN ( + SELECT id + FROM {context} + WHERE contextlevel >= 50)"; + $DB->execute($sql, $params); + + // Now migrate to real auth component names + $params = array('empty'=>$DB->sql_empty()); + $concat = $DB->sql_concat("'auth_'", 'component'); + $sql = "UPDATE {role_assignments} + SET component = $concat + WHERE component <> :empty + AND contextid IN ( + SELECT id + FROM {context} + WHERE contextlevel < 50)"; + $DB->execute($sql, $params); + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.22); + } + + if ($result && $oldversion < 2010061900.23) { + // add proper itemid to role assignments that were added by enrolment plugins + $sql = "UPDATE {role_assignments} + SET itemid = (SELECT MIN({enrol}.id) + FROM {enrol} + JOIN {context} ON ({context}.contextlevel = 50 AND {context}.instanceid = {enrol}.courseid) + WHERE {role_assignments}.component = ".$DB->sql_concat("'enrol_'", "{enrol}.enrol")." AND {context}.id = {role_assignments}.contextid) + WHERE component <> 'enrol_manual' AND component LIKE 'enrol_%'"; + $DB->execute($sql); + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.23); + } + + if ($result && $oldversion < 2010061900.30) { + // make new list of active enrol plugins - order is important, meta should be always last, manual first + $enabledplugins = explode(',', $CFG->enrol_plugins_enabled); + $enabledplugins = array_merge(array('manual', 'guest', 'self', 'cohort'), $enabledplugins); + if ($DB->record_exists('enrol', array('enrol'=>'meta'))) { + $enabledplugins[] = 'meta'; + } + $enabledplugins = array_unique($enabledplugins); + set_config('enrol_plugins_enabled', implode(',', $enabledplugins)); + + // Main savepoint reached + upgrade_main_savepoint($result, 2010061900.30); + } + + if ($result && $oldversion < 2010061900.31) { + // finalise all new enrol settings and cleanup old settings + + // legacy allowunenrol was deprecated in 1.9 already + unset_config('allwunenroll'); + + // obsolete course presets + unset_config('metacourse', 'moodlecourse'); + unset_config('enrol', 'moodlecourse'); + unset_config('enrollable', 'moodlecourse'); + unset_config('enrolperiod', 'moodlecourse'); + unset_config('expirynotify', 'moodlecourse'); + unset_config('notifystudents', 'moodlecourse'); + unset_config('expirythreshold', 'moodlecourse'); + unset_config('enrolpassword', 'moodlecourse'); + unset_config('guest', 'moodlecourse'); + + unset_config('backup_sche_metacourse', 'backup'); + + unset_config('lastexpirynotify'); + + // hidden course categories now prevent only browsing, courses are accessible if you know the URL and course is visible + unset_config('allowvisiblecoursesinhiddencategories'); + + if (isset($CFG->coursemanager)) { + set_config('coursecontact', $CFG->coursemanager); + unset_config('coursemanager'); + } + + // migrate plugin settings - the problem here is we are splitting manual into three different plugins + if (isset($CFG->enrol_manual_usepasswordpolicy)) { + set_config('usepasswordpolicy', $CFG->enrol_manual_usepasswordpolicy, 'enrol_guest'); + set_config('usepasswordpolicy', $CFG->enrol_manual_usepasswordpolicy, 'enrol_self'); + set_config('groupenrolmentkeypolicy', $CFG->enrol_manual_usepasswordpolicy); + unset_config('enrol_manual_usepasswordpolicy'); + } + if (isset($CFG->enrol_manual_requirekey)) { + set_config('requirepassword', $CFG->enrol_manual_requirekey, 'enrol_guest'); + set_config('requirepassword', $CFG->enrol_manual_requirekey, 'enrol_self'); + unset_config('enrol_manual_requirekey'); + } + if (isset($CFG->enrol_manual_showhint)) { + set_config('showhint', $CFG->enrol_manual_showhint, 'enrol_guest'); + set_config('showhint', $CFG->enrol_manual_showhint, 'enrol_self'); + unset_config('enrol_manual_showhint'); + } + + upgrade_main_savepoint($result, 2010061900.31); + } + + if ($result && $oldversion < 2010061900.32) { + // MDL-22797 course completion has to be updated to use new enrol framework, it will not be enabled in final 2.0 + set_config('enableavailability', 0); + set_config('enablecompletion', 0); + upgrade_main_savepoint($result, 2010061900.32); + } + + return $result; } //TODO: Cleanup before the 2.0 release - we do not want to drag along these dev machine fixes forever -// 1/ remove the automatic enabling of completion lib if debug enabled ( in 2008121701 block) // 2/ move 2009061300 block to the top of the file so that we may log upgrade queries // 3/ remove 2010033101 block // 4/ remove 2010032400 block diff --git a/lib/ddl/mysql_sql_generator.php b/lib/ddl/mysql_sql_generator.php index c84c08b6305..c7b893c6fb1 100644 --- a/lib/ddl/mysql_sql_generator.php +++ b/lib/ddl/mysql_sql_generator.php @@ -66,7 +66,7 @@ class mysql_sql_generator extends sql_generator { public $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY COLUMN COLUMNSPECS'; //The SQL template to alter columns - public $drop_index_sql = 'ALTER TABLE TABLENAME DROP INDEX INDEXNAME'; //SQL sentence to drop one index + public $drop_index_sql = 'ALTER TABLE TABLENAME DROP INDEX INDEXNAME'; //SQL sentence to drop one index - HACK for MDL-22804 //TABLENAME, INDEXNAME are dynamically replaced public $rename_index_sql = null; //SQL sentence to rename one index (MySQL doesn't support this!) @@ -94,6 +94,7 @@ class mysql_sql_generator extends sql_generator { return array("ALTER TABLE $this->prefix$tablename AUTO_INCREMENT = $value"); } + /** * Given one correct xmldb_table, returns the SQL statements * to create temporary table (inside one array) diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php index f23c3d9d70b..f533dd93a2f 100644 --- a/lib/deprecatedlib.php +++ b/lib/deprecatedlib.php @@ -39,6 +39,39 @@ function auth_get_plugin_title($authtype) { return get_string('pluginname', "auth_{$authtype}"); } + +/** + * Enrol someone without using the default role in a course + * @deprecated + */ +function enrol_into_course($course, $user, $enrol) { + error('Function enrol_into_course() was removed, please use new enrol plugins instead!'); +} + +/** + * Returns a role object that is the default role for new enrolments in a given course + * + * @deprecated + * @param object $course + * @return object returns a role or NULL if none set + */ +function get_default_course_role($course) { + debugging('Function get_default_course_role() is deprecated, please use individual enrol plugin settings instead!'); + + $student = get_archetype_roles('student'); + $student = reset($student); + + return $student; +} + +/** + * Extremely slow enrolled courses query. + * @deprecated + */ +function get_my_courses($userid, $sort='visible DESC,sortorder ASC', $fields=NULL, $doanything=false,$limit=0) { + error('Function get_my_courses() was removed, please use new enrol_get_my_courses() or enrol_get_users_courses()!'); +} + /** * Was returning list of translations, use new string_manager instead * diff --git a/lib/enrollib.php b/lib/enrollib.php new file mode 100644 index 00000000000..cf8171faf20 --- /dev/null +++ b/lib/enrollib.php @@ -0,0 +1,1284 @@ +. + +/** + * This library includes the basic parts of enrol api. + * It is available on each page. + * + * @package moodlecore + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + +/** Course enrol instance enabled. (used in enrol->status) */ +define('ENROL_INSTANCE_ENABLED', 0); + +/** Course enrol instance disabled, user may enter course if other enrol instance enabled. (used in enrol->status)*/ +define('ENROL_INSTANCE_DISABLED', 1); + +/** User is active participant (used in user_enrolments->status)*/ +define('ENROL_USER_ACTIVE', 0); + +/** User participation in course is suspended (used in user_enrolments->status) */ +define('ENROL_USER_SUSPENDED', 1); + +/** Enrol info is cached for this number of seconds in require_login() */ +define('ENROL_REQUIRE_LOGIN_CACHE_PERIOD', 1800); + +/** + * Returns instances of enrol plugins + * @param bool $enable return enabled only + * @return array of enrol plugins name=>instance + */ +function enrol_get_plugins($enabled) { + global $CFG; + + $result = array(); + + if ($enabled) { + // sorted by enabled plugin order + $enabled = explode(',', $CFG->enrol_plugins_enabled); + $plugins = array(); + foreach ($enabled as $plugin) { + $plugins[$plugin] = "$CFG->dirroot/enrol/$plugin"; + } + } else { + // sorted alphabetically + $plugins = get_plugin_list('enrol'); + ksort($plugins); + } + + foreach ($plugins as $plugin=>$location) { + if (!file_exists("$location/lib.php")) { + continue; + } + include_once("$location/lib.php"); + $class = "enrol_{$plugin}_plugin"; + if (!class_exists($class)) { + continue; + } + + $result[$plugin] = new $class(); + } + + return $result; +} + +/** + * Returns instance of enrol plugin + * @param string $name name of enrol plugin ('manual', 'guest', ...) + * @return enrol_plugin + */ +function enrol_get_plugin($name) { + global $CFG; + + if ($name !== clean_param($name, PARAM_SAFEDIR)) { + // ignore malformed plugin names completely + return null; + } + + $location = "$CFG->dirroot/enrol/$name"; + + if (!file_exists("$location/lib.php")) { + return null; + } + include_once("$location/lib.php"); + $class = "enrol_{$name}_plugin"; + if (!class_exists($class)) { + return null; + } + + return new $class(); +} + +/** + * Returns enrolment instances in given course. + * @param int $courseid + * @param bool $enabled + * @return array of enrol instances + */ +function enrol_get_instances($courseid, $enabled) { + global $DB, $CFG; + + if (!$enabled) { + return $DB->get_records('enrol', array('courseid'=>$courseid), 'sortorder,id'); + } + + $result = $DB->get_records('enrol', array('courseid'=>$courseid, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder,id'); + + $enabled = $enabled = explode(',', $CFG->enrol_plugins_enabled); + foreach ($result as $key=>$instance) { + if (!in_array($instance->enrol, $enabled)) { + unset($result[$key]); + continue; + } + if (!file_exists("$CFG->dirroot/enrol/$instance->enrol/lib.php")) { + // broken plugin + unset($result[$key]); + continue; + } + } + + return $result; +} + +/** + * Checks if a given plugin is in the list of enabled enrolment plugins. + * + * @param string $enrol Enrolment plugin name + * @return boolean Whether the plugin is enabled + */ +function enrol_is_enabled($enrol) { + global $CFG; + + if (empty($CFG->enrol_plugins_enabled)) { + return false; + } + return in_array($enrol, explode(',', $CFG->enrol_plugins_enabled)); +} + +/** + * Check all the login enrolment information for the given user object + * by querying the enrolment plugins + * + * @param object $user + * @return void + */ +function enrol_check_plugins($user) { + global $CFG; + + if (empty($user->id) or isguestuser($user)) { + // shortcut - there is no enrolment work for guests and not-logged-in users + return; + } + + static $inprogress = array(); // To prevent this function being called more than once in an invocation + + if (!empty($inprogress[$user->id])) { + return; + } + + $inprogress[$user->id] = true; // Set the flag + + $enabled = enrol_get_plugins(true); + + foreach($enabled as $enrol) { + $enrol->sync_user_enrolments($user); + } + + unset($inprogress[$user->id]); // Unset the flag +} + +/** + * This function adds necessary enrol plugins UI into the course edit form. + * + * @param MoodleQuickForm $mform + * @param object $data course edit form data + * @param object $context context of existing course or parent category if course does not exist + * @return void + */ +function enrol_course_edit_form(MoodleQuickForm $mform, $data, $context) { + $plugins = enrol_get_plugins(true); + if (!empty($data->id)) { + $instances = enrol_get_instances($data->id, false); + foreach ($instances as $instance) { + if (!isset($plugins[$instance->enrol])) { + continue; + } + $plugin = $plugins[$instance->enrol]; + $plugin->course_edit_form($instance, $mform, $data, $context); + } + } else { + foreach ($plugins as $plugin) { + $plugin->course_edit_form(NULL, $mform, $data, $context); + } + } +} + +/** + * Validate course edit form data + * + * @param array $data raw form data + * @param object $context context of existing course or parent category if course does not exist + * @return array errors array + */ +function enrol_course_edit_validation(array $data, $context) { + $errors = array(); + $plugins = enrol_get_plugins(true); + + if (!empty($data['id'])) { + $instances = enrol_get_instances($data['id'], false); + foreach ($instances as $instance) { + if (!isset($plugins[$instance->enrol])) { + continue; + } + $plugin = $plugins[$instance->enrol]; + $errors = array_merge($errors, $plugin->course_edit_validation($instance, $data, $context)); + } + } else { + foreach ($plugins as $plugin) { + $errors = array_merge($errors, $plugin->course_edit_validation(NULL, $data, $context)); + } + } + + return $errors; +} + +/** + * Update enrol instances after course edit form submission + * @param bool $inserted true means new course added, false course already existed + * @param object $course + * @param object $data form data + * @return void + */ +function enrol_course_updated($inserted, $course, $data) { + global $DB, $CFG; + + $plugins = enrol_get_plugins(true); + + foreach ($plugins as $plugin) { + $plugin->course_updated($inserted, $course, $data); + } +} + +/** + * Add navigation nodes + * @param navigation_node $coursenode + * @param object $course + * @return void + */ +function enrol_add_course_navigation(navigation_node $coursenode, $course) { + + $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); + + $instances = enrol_get_instances($course->id, true); + $plugins = enrol_get_plugins(true); + + // we do not want to break all course pages if there is some borked enrol plugin, right? + foreach ($instances as $k=>$instance) { + if (!isset($plugins[$instance->enrol])) { + unset($instances[$k]); + } + } + + $usersnode = $coursenode->add(get_string('users'), null, navigation_node::TYPE_CONTAINER); + + if ($course->id != SITEID) { + // list all participants - allows assing roles, groups, etc. + if (has_capability('moodle/course:enrolreview', $coursecontext)) { + $url = new moodle_url('/enrol/users.php', array('id'=>$course->id)); + $usersnode->add(get_string('enrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/users', '')); + } + + // manage enrol plugin instances + if (has_capability('moodle/course:enrolconfig', $coursecontext) or has_capability('moodle/course:enrolreview', $coursecontext)) { + $url = new moodle_url('/enrol/instances.php', array('id'=>$course->id)); + } else { + $url = NULL; + } + $instancesnode = $usersnode->add(get_string('enrolmentinstances', 'enrol'), $url); + + // each instance decides how to configure itself or how many other nav items are exposed + foreach ($instances as $instance) { + if (!isset($plugins[$instance->enrol])) { + continue; + } + $plugins[$instance->enrol]->add_course_navigation($instancesnode, $instance); + } + + if (!$url) { + $instancesnode->trim_if_empty(); + } + } + + // Manage groups in this course or even frontpage + if (($course->groupmode || !$course->groupmodeforce) && has_capability('moodle/course:managegroups', $coursecontext)) { + $url = new moodle_url('/group/index.php', array('id'=>$course->id)); + $usersnode->add(get_string('groups'), $url, navigation_node::TYPE_SETTING, null, 'groups', new pix_icon('i/group', '')); + } + + if (has_any_capability(array( 'moodle/role:assign', 'moodle/role:safeoverride','moodle/role:override', 'moodle/role:review'), $coursecontext)) { + // Override roles + if (has_capability('moodle/role:review', $coursecontext)) { + $url = new moodle_url('/admin/roles/permissions.php', array('contextid'=>$coursecontext->id)); + } else { + $url = NULL; + } + $permissionsnode = $usersnode->add(get_string('permissions', 'role'), $url); + + // Add assign or override roles if allowed + if ($course->id == SITEID or (!empty($CFG->adminsassignrolesincourse) and is_siteadmin())) { + if (has_capability('moodle/role:assign', $coursecontext)) { + $url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$coursecontext->id)); + $permissionsnode->add(get_string('assignedroles', 'role'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/roles', '')); + } + } + // Check role permissions + if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride','moodle/role:override', 'moodle/role:assign'), $coursecontext)) { + $url = new moodle_url('/admin/roles/check.php', array('contextid'=>$coursecontext->id)); + $permissionsnode->add(get_string('checkpermissions', 'role'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/checkpermissions', '')); + } + } + + // Deal somehow with users that are not enrolled but still got a role somehow + if ($course->id != SITEID) { + //TODO, create some new UI for role assignments at course level + if (has_capability('moodle/role:assign', $coursecontext)) { + $url = new moodle_url('/enrol/otherusers.php', array('id'=>$course->id)); + $usersnode->add(get_string('notenrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/roles', '')); + } + } + + // just in case nothing was actually added + $usersnode->trim_if_empty(); + + if ($course->id != SITEID) { + // Unenrol link + $unenrolprinted = false; + foreach ($instances as $instance) { + if (!isset($plugins[$instance->enrol])) { + continue; + } + $plugin = $plugins[$instance->enrol]; + if ($unenrollink = $plugin->get_unenrolself_link($instance)) { + $coursenode->add(get_string('unenrolme', 'core_enrol', format_string($course->shortname)), $unenrollink, navigation_node::TYPE_SETTING, null, 'unenrolself', new pix_icon('i/user', '')); + $unenrolprinted = true; + //TODO. deal with multiple unenrol links - not likely case, but still... + } + } + // Enrol link + if (!$unenrolprinted and !is_viewing($coursecontext) and !is_enrolled($coursecontext)) { + $url = new moodle_url('/enrol/index.php', array('id'=>$course->id)); + $coursenode->add(get_string('enrolme', 'core_enrol', format_string($course->shortname)), $url, navigation_node::TYPE_SETTING, null, 'enrolself', new pix_icon('i/user', '')); + } + } +} + +/** + * Returns list of courses current $USER is enrolled in and can access + * + * - $fields is an array of field names to ADD + * so name the fields you really need, which will + * be added and uniq'd + * + * @param strin|array $fields + * @param string $sort + * @param int $limit max number of courses + * @return array + */ +function enrol_get_my_courses($fields = NULL, $sort = 'visible DESC,sortorder ASC', $limit = 0) { + global $DB, $USER; + + // Guest account does not have any courses + if (isguestuser() or !isloggedin()) { + return(array()); + } + + $basefields = array('id', 'category', 'sortorder', + 'shortname', 'fullname', 'idnumber', + 'startdate', 'visible', + 'groupmode', 'groupmodeforce'); + + if (empty($fields)) { + $fields = $basefields; + } else if (is_string($fields)) { + // turn the fields from a string to an array + $fields = explode(',', $fields); + $fields = array_map('trim', $fields); + $fields = array_unique(array_merge($basefields, $fields)); + } else if (is_array($fields)) { + $fields = array_unique(array_merge($basefields, $fields)); + } else { + throw new coding_exception('Invalid $fileds parameter in enrol_get_my_courses()'); + } + if (in_array('*', $fields)) { + $fields = array('*'); + } + + $orderby = ""; + $sort = trim($sort); + if (!empty($sort)) { + $rawsorts = explode(',', $sort); + $sorts = array(); + foreach ($rawsorts as $rawsort) { + $rawsort = trim($rawsort); + if (strpos($rawsort, 'c.') === 0) { + $rawsort = substr($rawsort, 2); + } + $sorts[] = trim($rawsort); + } + $sort = 'c.'.implode(',c.', $sorts); + $orderby = "ORDER BY $sort"; + } + + $wheres = array("c.id <> :siteid"); + $params = array('siteid'=>SITEID); + + if (isset($USER->loginascontext) and $USER->loginascontext->contextlevel == CONTEXT_COURSE) { + // list _only_ this course - anything else is asking for trouble... + $wheres[] = "courseid = :loginas"; + $params['loginas'] = $USER->loginascontext->instanceid; + } + + $coursefields = 'c.' .join(',c.', $fields); + list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); + $wheres = " AND ".implode(" AND ", $wheres); + + $sql = "SELECT DISTINCT $coursefields $ccselect + FROM {course} c + JOIN {enrol} e ON (e.courseid = c.id AND e.status = :enabled) + JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid AND ue.status = :active) + $ccjoin + WHERE ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2) + $wheres + $orderby"; + $params['userid'] = $USER->id; + $params['active'] = ENROL_USER_ACTIVE; + $params['enabled'] = ENROL_INSTANCE_ENABLED; + $params['now1'] = round(time(), -2); // improves db caching + $params['now2'] = $params['now1']; + + $courses = $DB->get_records_sql($sql, $params, 0, $limit); + + // preload contexts and check visibility + foreach ($courses as $id=>$course) { + context_instance_preload($course); + if (!$course->visible) { + if (!$context = get_context_instance(CONTEXT_COURSE, $id)) { + unset($course[$id]); + continue; + } + if (!has_capability('moodle/course:viewhiddencourses', $context)) { + unset($course[$id]); + continue; + } + } + $courses[$id] = $course; + } + + //wow! Is that really all? :-D + + return $courses; +} + +/** + * Returns list of courses user is enrolled into. + * + * - $fields is an array of fieldnames to ADD + * so name the fields you really need, which will + * be added and uniq'd + * + * @param int $userid + * @param bool $onlyactive return only active enrolments in courses user may see + * @param strin|array $fields + * @param string $sort + * @return array + */ +function enrol_get_users_courses($userid, $onlyactive = false, $fields = NULL, $sort = 'visible DESC,sortorder ASC') { + global $DB; + + // Guest account does not have any courses + if (isguestuser($userid) or !empty($userid)) { + return(array()); + } + + $basefields = array('id', 'category', 'sortorder', + 'shortname', 'fullname', 'idnumber', + 'startdate', 'visible', + 'groupmode', 'groupmodeforce'); + + if (empty($fields)) { + $fields = $basefields; + } else if (is_string($fields)) { + // turn the fields from a string to an array + $fields = explode(',', $fields); + $fields = array_map('trim', $fields); + $fields = array_unique(array_merge($basefields, $fields)); + } else if (is_array($fields)) { + $fields = array_unique(array_merge($basefields, $fields)); + } else { + throw new coding_exception('Invalid $fileds parameter in enrol_get_my_courses()'); + } + if (in_array('*', $fields)) { + $fields = array('*'); + } + + $orderby = ""; + $sort = trim($sort); + if (!empty($sort)) { + $rawsorts = explode(',', $sort); + $sorts = array(); + foreach ($rawsorts as $rawsort) { + $rawsort = trim($rawsort); + if (strpos($rawsort, 'c.') === 0) { + $rawsort = substr($rawsort, 2); + } + $sorts[] = trim($rawsort); + } + $sort = 'c.'.implode(',c.', $sorts); + $orderby = "ORDER BY $sort"; + } + + $wheres = array("c.id <> :siteid"); + $params = array('siteid'=>SITEID); + + if ($onlyactive) { + $wheres[] = "ue.status = :active"; + $wheres[] = "e.status = :enabled"; + $wheres[] = "ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)"; + $params['now1'] = round(time(), -2); // improves db caching + $params['now2'] = $params['now1']; + $params['active'] = ENROL_USER_ACTIVE; + $params['enabled'] = ENROL_INSTANCE_ENABLED; + } + + $coursefields = 'c.' .join(',c.', $fields); + list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); + $wheres = "WHERE ".implode(" AND ", $wheres); + + $sql = "SELECT DISTINCT $coursefields $ccselect + FROM {course} c + JOIN {enrol} e ON (e.courseid = c.id) + JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid) + $ccjoin + $wheres + $orderby"; + $params['userid'] = $USER->id; + + $courses = $DB->get_records_sql($sql, $params); + + // preload contexts and check visibility + foreach ($courses as $id=>$course) { + context_instance_preload($course); + if ($onlyactive) { + if (!$course->visible) { + if (!$context = get_context_instance(CONTEXT_COURSE, $id)) { + unset($course[$id]); + continue; + } + if (!has_capability('moodle/course:viewhiddencourses', $context, $userid)) { + unset($course[$id]); + continue; + } + } + } + $courses[$id] = $course; + } + + //wow! Is that really all? :-D + + return $courses; + +} + +/** + * Called when user is about to be deleted. + * @param object $user + * @return void + */ +function enrol_user_delete($user) { + global $DB; + + $plugins = enrol_get_plugins(true); + foreach ($plugins as $plugin) { + $plugin->user_delete($user); + } + + // force cleanup of all broken enrolments + $DB->delete_records('user_enrolments', array('userid'=>$user->id)); +} + +/** + * Try to enrol user via default internal auth plugin. + * + * For now this is always using the manual enrol plugin... + * + * @param $courseid + * @param $userid + * @param $roleid + * @param $timestart + * @param $timeend + * @return bool success + */ +function enrol_try_internal_enrol($courseid, $userid, $roleid = null, $timestart = 0, $timeend = 0) { + global $DB; + + //note: this is hardcoded to manual plugin for now + + if (!enrol_is_enabled('manual')) { + return false; + } + + if (!$enrol = enrol_get_plugin('manual')) { + return false; + } + if (!$instances = $DB->get_records('enrol', array('enrol'=>'manual', 'courseid'=>$courseid, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder,id ASC')) { + return false; + } + $instance = reset($instances); + + $enrol->enrol_user($instance, $userid, $roleid, $timestart, $timeend); + + return true; +} + +/** + * All enrol plugins should be based on this class, + * this is also the main source of documentation. + */ +abstract class enrol_plugin { + protected $config = null; + + /** + * Returns name of this enrol plugin + * @return string + */ + public function get_name() { + // second word in class is always enrol name + $words = explode('_', get_class($this)); + return $words[1]; + } + + /** + * Returns localised name of enrol instance + * + * @param object $instance (null is accepted too) + * @return string + */ + public function get_instance_name($instance) { + if (empty($instance->name)) { + $enrol = $this->get_name(); + return get_string('pluginname', 'enrol_'.$enrol); + } else { + return format_string($instance->name); + } + } + + /** + * Makes sure config is loaded and cached. + * @return void + */ + protected function load_config() { + if (!isset($this->config)) { + $name = $this->get_name(); + if (!$config = get_config("enrol_$name")) { + $config = new object(); + } + $this->config = $config; + } + } + + /** + * Returns plugin config value + * @param string $name + * @param string $default value if config does not exist yet + * @return string value or default + */ + public function get_config($name, $default = NULL) { + $this->load_config(); + return isset($this->config->$name) ? $this->config->$name : $default; + } + + /** + * Sets plugin config value + * @param string $name name of config + * @param string $value string config value, null means delete + * @return string value + */ + public function set_config($name, $value) { + $name = $this->get_name(); + $this->load_config(); + if ($value === NULL) { + unset($this->config->$name); + } else { + $this->config->$name = $value; + } + set_config($name, $value, "enrol_$name"); + } + + /** + * Does this plugin assign protected roles are can they be manually removed? + * @return bool - false means anybody may tweak roles, it does not use itemid and component when assigning roles + */ + public function roles_protected() { + return true; + } + + /** + * Does this plugin allow manual unenrolments? + * + * @param stdClass $instance course enrol instance + * ALl plugins allowing this must implement 'enrol/xxx:unenrol' capability + * + * @return bool - true means anybody may unenrol others freely, trues means nobody may touch user_enrolments + */ + public function allow_unenrol(stdClass $instance) { + return false; + } + + /** + * Does this plugin allow manual changes in user_enrolments table? + * + * ALl plugins allowing this must implement 'enrol/xxx:manage' capability + * + * @param stdClass $instance course enrol instance + * @return bool - true means it is possible to change enrol period and status in user_enrolments table + */ + public function allow_manage(stdClass $instance) { + return false; + } + + /** + * Attempt to automatically enrol current user in course without any interaction, + * calling code has to make sure the plugin and instance are active. + * + * @param stdClass $instance course enrol instance + * @param stdClass $user record + * @return bool|int false means not enrolled, integer means timeend + */ + public function try_autoenrol(stdClass $instance) { + global $USER; + + return false; + } + + /** + * Attempt to automatically gain temporary guest access to course, + * calling code has to make sure the plugin and instance are active. + * + * @param stdClass $instance course enrol instance + * @param stdClass $user record + * @return bool|int false means no guest access, integer means timeend + */ + public function try_guestaccess(stdClass $instance) { + global $USER; + + return false; + } + + /** + * Enrol user into course via enrol instance. + * + * @param stdClass $instance + * @param int $userid + * @param int $roleid optional role id + * @param int $timestart + * @param int $timeend + * @return void + */ + public function enrol_user(stdClass $instance, $userid, $roleid = null, $timestart = 0, $timeend = 0) { + global $DB, $USER, $CFG; // CFG necessary!!! + + if ($instance->courseid == SITEID) { + throw new coding_exception('invalid attempt to enrol into frontpage course!'); + } + + $name = $this->get_name(); + $courseid = $instance->courseid; + + if ($instance->enrol !== $name) { + throw new coding_exception('invalid enrol instance!'); + } + $context = get_context_instance(CONTEXT_COURSE, $instance->courseid, MUST_EXIST); + + $inserted = false; + if ($ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) { + if ($ue->timestart != $timestart or $ue->timeend != $timeend) { + $ue->timestart = $timestart; + $ue->timeend = $timeend; + $ue->modifier = $USER->id; + $ue->timemodified = time(); + $DB->update_record('user_enrolments', $ue); + } + } else { + $ue = new object(); + $ue->enrolid = $instance->id; + $ue->status = ENROL_USER_ACTIVE; + $ue->userid = $userid; + $ue->timestart = $timestart; + $ue->timeend = $timeend; + $ue->modifier = $USER->id; + $ue->timemodified = time(); + $ue->id = $DB->insert_record('user_enrolments', $ue); + + $inserted = true; + } + + if ($roleid) { + if ($this->roles_protected()) { + role_assign($roleid, $userid, $context->id, 'enrol_'.$name, $instance->id); + } else { + role_assign($roleid, $userid, $context->id); + } + } + + if ($inserted) { + // add extra info and trigger event + $ue->courseid = $courseid; + $ue->enrol = $name; + events_trigger('user_enrolled', $ue); + } + + // reset primitive require_login() caching + if ($userid == $USER->id) { + if (isset($USER->enrol['enrolled'][$courseid])) { + unset($USER->enrol['enrolled'][$courseid]); + } + if (isset($USER->enrol['tempguest'][$courseid])) { + unset($USER->enrol['tempguest'][$courseid]); + $USER->access = remove_temp_roles($context, $USER->access); + } + } + } + + /** + * Store user_enrolments changes and trigger event. + * + * @param object $ue + * @param int $user id + * @param int $status + * @param int $timestart + * @param int $timeend + * @return void + */ + public function update_user_enrol(stdClass $instance, $userid, $status = NULL, $timestart = NULL, $timeend = NULL) { + global $DB, $USER; + + $name = $this->get_name(); + + if ($instance->enrol !== $name) { + throw new coding_exception('invalid enrol instance!'); + } + + if (!$ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) { + // weird, user not enrolled + return; + } + + $modified = false; + if (isset($status) and $ue->status != $status) { + $ue->status = $status; + $modified = true; + } + if (isset($timestart) and $ue->timestart != $timestart) { + $ue->timestart = $timestart; + $modified = true; + } + if (isset($timeend) and $ue->timeend != $timeend) { + $ue->timeend = $timeend; + $modified = true; + } + + if (!$modified) { + // no change + return; + } + + $ue->modifierid = $USER->id; + $DB->update_record('user_enrolments', $ue); + + // trigger event + $ue->courseid = $instance->courseid; + $ue->enrol = $instance->name; + events_trigger('user_unenrol_modified', $ue); + } + + /** + * Unenrol user from course, + * the last unenrolment removes all remaining roles. + * + * @param stdClass $instance + * @param int $userid + * @return void + */ + public function unenrol_user(stdClass $instance, $userid) { + global $CFG, $USER, $DB; + + $name = $this->get_name(); + $courseid = $instance->courseid; + + if ($instance->enrol !== $name) { + throw new coding_exception('invalid enrol instance!'); + } + $context = get_context_instance(CONTEXT_COURSE, $instance->courseid, MUST_EXIST); + + if (!$ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) { + // weird, user not enrolled + return; + } + + role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_'.$name, 'itemid'=>$instance->id)); + $DB->delete_records('user_enrolments', array('id'=>$ue->id)); + + // add extra info and trigger event + $ue->courseid = $courseid; + $ue->enrol = $name; + + $sql = "SELECT 'x' + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid) + WHERE ue.userid = :userid AND e.courseid = :courseid"; + if ($DB->record_exists_sql($sql, array('userid'=>$userid, 'courseid'=>$courseid))) { + $ue->lastenrol = false; + events_trigger('user_unenrolled', $ue); + // user still has some enrolments, no big cleanup yet + } else { + // the big cleanup IS necessary! + + require_once("$CFG->dirroot/group/lib.php"); + require_once("$CFG->libdir/gradelib.php"); + + // remove all remaining roles + role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id), true, false); + + //clean up ALL invisible user data from course if this is the last enrolment - groups, grades, etc. + groups_delete_group_members($courseid, $userid); + + grade_user_unenrol($courseid, $userid); + + $DB->delete_records('user_lastaccess', array('userid'=>$userid, 'courseid'=>$courseid)); + + $ue->lastenrol = false; + events_trigger('user_unenrolled', $ue); + } + // reset primitive require_login() caching + if ($userid == $USER->id) { + if (isset($USER->enrol['enrolled'][$courseid])) { + unset($USER->enrol['enrolled'][$courseid]); + } + if (isset($USER->enrol['tempguest'][$courseid])) { + unset($USER->enrol['tempguest'][$courseid]); + $USER->access = remove_temp_roles($context, $USER->access); + } + } + } + + /** + * Forces synchronisation of user enrolments. + * + * This is important especially for external enrol plugins, + * this function is called for all enabled enrol plugins + * right after every user login. + * + * @param object $user user record + * @return void + */ + public function sync_user_enrolments($user) { + // override if necessary + } + + /** + * 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_candidate_link($courseid) { + // override for most plugins, check if instance already exists in cases only one instance is supported + return NULL; + } + + /** + * Is it possible to delete enrol instance via standard UI? + * + * @param object $instance + * @return bool + */ + public function instance_deleteable($instance) { + return true; + } + + /** + * Returns link to manual enrol UI if exists. + * Does the access control tests automatically. + * + * @param object $instance + * @return moodle_url + */ + public function get_manual_enrol_link($instance) { + return NULL; + } + + /** + * Returns list of unenrol links for all enrol instances in course. + * + * @param int $courseid + * @return moodle_url + */ + public function get_unenrolself_link($instance) { + global $USER, $CFG, $DB; + + $name = $this->get_name(); + if ($instance->enrol !== $name) { + throw new coding_exception('invalid enrol instance!'); + } + + if ($instance->courseid == SITEID) { + return NULL; + } + + if (!enrol_is_enabled($name)) { + return NULL; + } + + if ($instance->status != ENROL_INSTANCE_ENABLED) { + return NULL; + } + + $context = get_context_instance(CONTEXT_COURSE, $instance->courseid, MUST_EXIST); + $courseid = $instance->courseid; + + if (!file_exists("$CFG->dirroot/enrol/$name/unenrolself.php")) { + return NULL; + } + + $context = get_context_instance(CONTEXT_COURSE, $courseid); + if (!has_capability("enrol/$name:unenrolself", $context)) { + return NULL; + } + + if (!$DB->record_exists('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$USER->id, 'status'=>ENROL_USER_ACTIVE))) { + return NULL; + } + + return new moodle_url("/enrol/$name/unenrolself.php", array('enrolid'=>$instance->id));; + } + + /** + * Adds enrol instance UI to course edit form + * + * @param object $instance enrol instance or null if does not exist yet + * @param MoodleQuickForm $mform + * @param object $data + * @param object $context context of existing course or parent category if course does not exist + * @return void + */ + public function course_edit_form($instance, MoodleQuickForm $mform, $data, $context) { + // override - usually at least enable/disable switch, has to add own form header + } + + /** + * Validates course edit form data + * + * @param object $instance enrol instance or null if does not exist yet + * @param array $data + * @param object $context context of existing course or parent category if course does not exist + * @return array errors array + */ + public function course_edit_validation($instance, array $data, $context) { + return array(); + } + + /** + * Called after updating/inserting course. + * + * @param bool $inserted true if course just inserted + * @param object $course + * @param object $data form data + * @return void + */ + public function course_updated($inserted, $course, $data) { + // override if settings on course edit page or some automatic sync needed + } + + /** + * Add new instance of enrol plugin settings. + * @param object $course + * @param array instance fields + * @return int id of new instance + */ + public function add_instance($course, array $fields = NULL) { + global $DB; + + if ($course->id == SITEID) { + throw new coding_exception('Invalid request to add enrol instance to frontpage.'); + } + + $instance = new object(); + $instance->enrol = $this->get_name(); + $instance->status = ENROL_INSTANCE_ENABLED; + $instance->courseid = $course->id; + $instance->enrolstartdate = 0; + $instance->enrolenddate = 0; + $instance->timemodified = time(); + $instance->timecreated = $instance->timemodified; + $instance->sortorder = $DB->get_field('enrol', 'COALESCE(MAX(sortorder), -1) + 1', array('courseid'=>$course->id)); + + $fields = (array)$fields; + unset($fields['enrol']); + unset($fields['courseid']); + unset($fields['sortorder']); + foreach($fields as $field=>$value) { + $instance->$field = $value; + } + + return $DB->insert_record('enrol', $instance); + } + + /** + * Add new instance of enrol plugin with default settings, + * called when adding new instance manually or when adding new course. + * + * Not all plugins support this. + * + * @param object $course + * @return int id of new instance or null if no default supported + */ + public function add_default_instance($course) { + return null; + } + + /** + * Delete course enrol plugin instance, unenrol all users. + * @param object $instance + * @return void + */ + public function delete_instance($instance) { + global $DB; + + $name = $this->get_name(); + if ($instance->enrol !== $name) { + throw new coding_exception('invalid enrol instance!'); + } + + //first unenrol all users + $participants = $DB->get_recordset('user_enrolments', array('enrolid'=>$instance->id)); + foreach ($participants as $participant) { + $this->unenrol_user($instance, $participant->userid); + } + $participants->close(); + + // now clean up all remainders that were not removed correctly + $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>$name)); + $DB->delete_records('user_enrolments', array('enrolid'=>$instance->id)); + + // finally drop the enrol row + $DB->delete_records('enrol', array('id'=>$instance->id)); + } + + /** + * 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) { + return null; + } + + /** + * Adds navigation links into course admin block. + * + * By defaults looks for manage links only. + * + * @param navigation_node $instancesnode + * @param object $instance + * @return moodle_url; + */ + public function add_course_navigation($instancesnode, stdClass $instance) { + if ($managelink = $this->get_manage_link($instance)) { + $instancesnode->add($this->get_instance_name($instance), $managelink, navigation_node::TYPE_SETTING); + } + } + + /** + * Returns enrolment instance manage link. + * + * By defaults looks for manage.php file and tests for manage capability. + * + * @param object $instance + * @return moodle_url; + */ + public function get_manage_link($instance) { + global $CFG, $DB; + + $name = $this->get_name(); + + if ($instance->enrol !== $name) { + throw new coding_exception('Invalid enrol instance type!'); + } + + if (!file_exists("$CFG->dirroot/enrol/$name/manage.php")) { + return NULL; + } + + if ($instance->courseid == SITEID) { + // no enrolments on the frontpage, only roles there allowed + return NULL; + } + + $context = get_context_instance(CONTEXT_COURSE, $instance->courseid); + if (!has_capability('enrol/'.$name.':manage', $context)) { + return NULL; + } + + return new moodle_url("/enrol/$name/manage.php", array('enrolid'=>$instance->id)); + } + + /** + * Reads version.php and determines if it is necessary + * to execute the cron job now. + * @return bool + */ + public function is_cron_required() { + global $CFG; + + $name = $this->get_name(); + $versionfile = "$CFG->dirroot/enrol/$name/version.php"; + $plugin = new object(); + include($versionfile); + if (empty($plugin->cron)) { + return false; + } + $lastexecuted = $this->get_config('lastcron', 0); + if ($lastexecuted + $plugin->cron < time()) { + return true; + } else { + return false; + } + } + + /** + * Called for all enabled enrol plugins that returned true from is_cron_required(). + * @return void + */ + public function cron() { + } + + /** + * Called when user is about to be deleted + * @param object $user + * @return void + */ + public function user_delete($user) { + global $DB; + + $sql = "SELECT e.* + FROM {enrol} e + JOIN {user_enrolments} ue ON (ue.courseid = e.courseid) + WHERE e.enrol = :meta AND ue.userid = :userid"; + $params = array('name'=>$this->get_name(), 'userid'=>$user->id); + + $rs = $DB->get_records_recordset($sql, $params); + foreach($rs as $instance) { + $this->unenrol_user($instance, $user->id); + } + $rs->close(); + } +} + diff --git a/lib/eventslib.php b/lib/eventslib.php index bcee5a7f0f0..49fb7d6cace 100755 --- a/lib/eventslib.php +++ b/lib/eventslib.php @@ -472,6 +472,12 @@ function events_trigger($eventname, $eventdata) { $dump = ''; $callers = debug_backtrace(); foreach ($callers as $caller) { + if (!isset($caller['line'])) { + $caller['line'] = '?'; + } + if (!isset($caller['file'])) { + $caller['file'] = '?'; + } $dump .= 'line ' . $caller['line'] . ' of ' . substr($caller['file'], strlen($CFG->dirroot) + 1); if (isset($caller['function'])) { $dump .= ': call to '; diff --git a/lib/externallib.php b/lib/externallib.php index c8742185e46..d4289dc327b 100644 --- a/lib/externallib.php +++ b/lib/externallib.php @@ -307,25 +307,7 @@ class external_api { if ($context->contextlevel >= CONTEXT_COURSE) { list($context, $course, $cm) = get_context_info_array($context->id); - // must be enrolled or viewing - if (!is_enrolled($context) and !is_viewing($context)) { - throw new invalid_parameter_exception('Must be enrolled in course or be allowed to inspect it.'); - } - // make sure the course is actually visible - if (!($course->visible && course_parent_visible($COURSE)) && !has_capability('moodle/course:viewhiddencourses', get_context_instance(CONTEXT_COURSE, $course->id))) { - throw new invalid_parameter_exception('Invalid course.'); - } - // make sure the activity is actually visible - if ($cm && !$cm->visible && !has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_MODULE, $cm->id))) { - throw new invalid_parameter_exception('Invalid activity.'); - } - // verify group memebers - if (!empty($CFG->enablegroupmembersonly) and $cm and $cm->groupmembersonly and !has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id))) { - if (!groups_has_membership($cm)) { - throw new invalid_parameter_exception('Must be member of at least one group.'); - } - } - //TODO: verify course completion + require_login($course, false, $cm, false, true); } } } @@ -468,7 +450,7 @@ function external_generate_token($tokentype, $serviceorid, $userid, $contextorid return $newtoken->token; } /** - * Create and return a session linked token. Token to be used for html embedded client apps that want to communicate + * Create and return a session linked token. Token to be used for html embedded client apps that want to communicate * with the Moodle server through web services. The token is linked to the current session for the current page request. * It is expected this will be called in the script generating the html page that is embedding the client app and that the * returned token will be somehow passed into the client app being embedded in the page. diff --git a/lib/file/file_browser.php b/lib/file/file_browser.php index 399c8488c7c..752bd60c732 100644 --- a/lib/file/file_browser.php +++ b/lib/file/file_browser.php @@ -318,7 +318,7 @@ class file_browser { return null; } - if (!is_null($filearea) and !in_array($filearea, array('course_intro', 'course_content', 'course_section', 'course_backup', 'section_backup'))) { + if (!is_null($filearea) and !in_array($filearea, array('course_summary', 'course_content', 'course_section', 'course_backup', 'section_backup'))) { // file area does not exist, sorry $filearea = null; } @@ -344,7 +344,7 @@ class file_browser { return null; } - private function get_file_info_course_intro($course, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) { + private function get_file_info_course_summary($course, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) { global $CFG; $fs = get_file_storage(); diff --git a/lib/file/file_info_course.php b/lib/file/file_info_course.php index 9d6e825a5b7..3cdd866a2c0 100644 --- a/lib/file/file_info_course.php +++ b/lib/file/file_info_course.php @@ -78,7 +78,7 @@ class file_info_course extends file_info { public function get_children() { $children = array(); - if ($child = $this->browser->get_file_info($this->context, 'course_intro', 0)) { + if ($child = $this->browser->get_file_info($this->context, 'course_summary', 0)) { $children[] = $child; } if ($child = $this->browser->get_file_info($this->context, 'course_section')) { diff --git a/lib/gradelib.php b/lib/gradelib.php index af512664b44..f44c7698382 100644 --- a/lib/gradelib.php +++ b/lib/gradelib.php @@ -1208,6 +1208,34 @@ function grade_uninstalled_module($modname) { } } +/** + * Deletes all user data from gradebook. + * @param $userid + */ +function grade_user_delete($userid) { + if ($grades = grade_grade::fetch_all(array('userid'=>$userid))) { + foreach ($grades as $grade) { + $grade->delete('userdelete'); + } + } +} + +/** + * Purge course data when user unenrolled. + * @param $userid + */ +function grade_user_unenrol($courseid, $userid) { + if ($items = grade_item::fetch_all(array('courseid'=>$courseid))) { + foreach ($items as $item) { + if ($grades = grade_grade::fetch_all(array('userid'=>$userid, 'itemid'=>$item->id))) { + foreach ($grades as $grade) { + $grade->delete('userdelete'); + } + } + } + } +} + /** * Grading cron job * diff --git a/lib/moodlelib.php b/lib/moodlelib.php index b9496992d22..8c796fd379a 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -2147,60 +2147,65 @@ function get_login_url($loginguest=false) { * When $cm parameter specified, this function sets page layout to 'module'. * You need to change it manually later if some other layout needed. * - * @global object - * @global object - * @global object - * @global object - * @global string - * @global object - * @global object - * @global object - * @uses SITEID Define * @param mixed $courseorid id of the course or course object * @param bool $autologinguest default true * @param object $cm course module object * @param bool $setwantsurltome Define if we want to set $SESSION->wantsurl, defaults to * true. Used to avoid (=false) some scripts (file.php...) to set that variable, * in order to keep redirects working properly. MDL-14495 + * @param bool $preventredirect set to true in scripts that can not redirect (CLI, rss feeds, etc.), throws exceptions * @return mixed Void, exit, and die depending on path */ -function require_login($courseorid=0, $autologinguest=true, $cm=null, $setwantsurltome=true) { - global $CFG, $SESSION, $USER, $COURSE, $FULLME, $PAGE, $SITE, $DB, $OUTPUT; +function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $setwantsurltome = true, $preventredirect = false) { + global $CFG, $SESSION, $USER, $FULLME, $PAGE, $SITE, $DB, $OUTPUT; -/// setup global $COURSE, themes, language and locale + // setup global $COURSE, themes, language and locale if (!empty($courseorid)) { if (is_object($courseorid)) { $course = $courseorid; } else if ($courseorid == SITEID) { $course = clone($SITE); } else { - $course = $DB->get_record('course', array('id' => $courseorid)); - if (!$course) { - throw new moodle_exception('invalidcourseid'); - } + $course = $DB->get_record('course', array('id' => $courseorid), '*', MUST_EXIST); } if ($cm) { + if ($cm->course != $course->id) { + throw new coding_exception('course and cm parameters in require_login() call do not match!!'); + } $PAGE->set_cm($cm, $course); // set's up global $COURSE $PAGE->set_pagelayout('incourse'); } else { $PAGE->set_course($course); // set's up global $COURSE } } else { - // do not touch global $COURSE via $PAGE->set_course() !! + // do not touch global $COURSE via $PAGE->set_course(), + // the reasons is we need to be able to call require_login() at any time!! + $course = $SITE; + if ($cm) { + throw new coding_exception('cm parameter in require_login() requires valid course parameter!'); + } } -/// If the user is not even logged in yet then make sure they are + // If the user is not even logged in yet then make sure they are if (!isloggedin()) { //NOTE: $USER->site check was obsoleted by session test cookie, // $USER->confirmed test is in login/index.php + if ($preventredirect) { + throw new require_login_exception('You are not logged in'); + } + if ($setwantsurltome) { $SESSION->wantsurl = $FULLME; } if (!empty($_SERVER['HTTP_REFERER'])) { $SESSION->fromurl = $_SERVER['HTTP_REFERER']; } - if ($autologinguest and !empty($CFG->guestloginbutton) and !empty($CFG->autologinguests) and ($COURSE->id == SITEID or $COURSE->guest) ) { - $loginguest = true; + if ($autologinguest and !empty($CFG->guestloginbutton) and !empty($CFG->autologinguests)) { + if ($course->id == SITEID) { + $loginguest = true; + } else { + $loginguest = false; + } } else { $loginguest = false; } @@ -2208,19 +2213,19 @@ function require_login($courseorid=0, $autologinguest=true, $cm=null, $setwantsu exit; // never reached } -/// loginas as redirection if needed - if ($COURSE->id != SITEID and session_is_loggedinas()) { + // loginas as redirection if needed + if ($course->id != SITEID and session_is_loggedinas()) { if ($USER->loginascontext->contextlevel == CONTEXT_COURSE) { - if ($USER->loginascontext->instanceid != $COURSE->id) { + if ($USER->loginascontext->instanceid != $course->id) { print_error('loginasonecourse', '', $CFG->wwwroot.'/course/view.php?id='.$USER->loginascontext->instanceid); } } } -/// check whether the user should be changing password (but only if it is REALLY them) + // check whether the user should be changing password (but only if it is REALLY them) if (get_user_preferences('auth_forcepasswordchange') && !session_is_loggedinas()) { $userauth = get_auth_plugin($USER->auth); - if ($userauth->can_change_password()) { + if ($userauth->can_change_password() and !$preventredirect) { $SESSION->wantsurl = $FULLME; if ($changeurl = $userauth->change_password_url()) { //use plugin custom url @@ -2239,46 +2244,212 @@ function require_login($courseorid=0, $autologinguest=true, $cm=null, $setwantsu } } -/// Check that the user account is properly set up + // Check that the user account is properly set up if (user_not_fully_set_up($USER)) { + if ($preventredirect) { + throw new require_login_exception('User not fully set-up'); + } $SESSION->wantsurl = $FULLME; redirect($CFG->wwwroot .'/user/edit.php?id='. $USER->id .'&course='. SITEID); } -/// Make sure the USER has a sesskey set up. Used for checking script parameters. + // Make sure the USER has a sesskey set up. Used for CSRF protection. sesskey(); + // Do not bother admins with any formalities, no last access updates either + if (is_siteadmin()) { + return; + } + // Check that the user has agreed to a site policy if there is one if (!empty($CFG->sitepolicy)) { + if ($preventredirect) { + throw new require_login_exception('Policy not agreed'); + } if (!$USER->policyagreed) { $SESSION->wantsurl = $FULLME; redirect($CFG->wwwroot .'/user/policy.php'); } } - // Fetch the system context, we are going to use it a lot. + // Fetch the system context, the course context, and prefetch its child contexts $sysctx = get_context_instance(CONTEXT_SYSTEM); + $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + if ($cm) { + $cmcontext = get_context_instance(CONTEXT_MODULE, $cm->id, MUST_EXIST); + } else { + $cmcontext = null; + } -/// If the site is currently under maintenance, then print a message + // If the site is currently under maintenance, then print a message if (!empty($CFG->maintenance_enabled) and !has_capability('moodle/site:config', $sysctx)) { + if ($preventredirect) { + throw new require_login_exception('Maintenance in progress'); + } + print_maintenance_message(); } -/// groupmembersonly access control + // make sure the course itself is not hidden + if ($course->id == SITEID) { + // frontpage can not be hidden + } else { + if (!empty($USER->access['rsw'][$coursecontext->path])) { + // when switching roles ignore the hidden flag - user had to be in course to do the switch + } else { + if (!$course->visible and !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { + // originally there was also test of parent category visibility, + // BUT is was very slow in complex queries involving "my courses" + // now it is also possible to simply hide all courses user is not enrolled in :-) + if ($preventredirect) { + throw new require_login_exception('Course is hidden'); + } + notice(get_string('coursehidden'), $CFG->wwwroot .'/'); + } + } + } + + // is the user enrolled? + if ($course->id == SITEID) { + // everybody is enrolled on the frontpage + + } else { + if (session_is_loggedinas()) { + // Make sure the REAL person can access this course first + $realuser = session_get_realuser(); + if (!is_enrolled($coursecontext, $realuser->id, '', true) and !is_viewing($coursecontext, $realuser->id) and !is_siteadmin($realuser->id)) { + if ($preventredirect) { + throw new require_login_exception('Invalid course login-as access'); + } + echo $OUTPUT->header(); + notice(get_string('studentnotallowed', '', fullname($USER, true)), $CFG->wwwroot .'/'); + } + } + + // very simple enrolment caching - changes in course setting are not reflected immediately + if (!isset($USER->enrol)) { + $USER->enrol = array(); + $USER->enrol['enrolled'] = array(); + $USER->enrol['tempguest'] = array(); + } + + $access = false; + + if (is_viewing($coursecontext, $USER)) { + // ok, no need to mess with enrol + $access = true; + + } else { + if (isset($USER->enrol['enrolled'][$course->id])) { + if ($USER->enrol['enrolled'][$course->id] == 0) { + $access = true; + } else if ($USER->enrol['enrolled'][$course->id] > time()) { + $access = true; + } else { + //expired + unset($USER->enrol['enrolled'][$course->id]); + } + } + if (isset($USER->enrol['tempguest'][$course->id])) { + if ($USER->enrol['tempguest'][$course->id] == 0) { + $access = true; + } else if ($USER->enrol['tempguest'][$course->id] > time()) { + $access = true; + } else { + //expired + unset($USER->enrol['tempguest'][$course->id]); + $USER->access = remove_temp_roles($coursecontext, $USER->access); + } + } + + if ($access) { + // cache ok + } else if (is_enrolled($coursecontext, $USER, '', true)) { + // active participants may always access + // TODO: refactor this into some new function + $now = time(); + $sql = "SELECT MAX(ue.timeend) + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid) + JOIN {user} u ON u.id = ue.userid + WHERE ue.userid = :userid AND ue.status = :active AND e.status = :enabled AND u.deleted = 0 + AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)"; + $params = array('enabled'=>ENROL_INSTANCE_ENABLED, 'active'=>ENROL_USER_ACTIVE, + 'userid'=>$USER->id, 'courseid'=>$coursecontext->instanceid, 'now1'=>$now, 'now2'=>$now); + $until = $DB->get_field_sql($sql, $params); + if (!$until or $until > time() + ENROL_REQUIRE_LOGIN_CACHE_PERIOD) { + $until = time() + ENROL_REQUIRE_LOGIN_CACHE_PERIOD; + } + + $USER->enrol['enrolled'][$course->id] = $until; + $access = true; + + // remove traces of previous temp guest access + $USER->access = remove_temp_roles($coursecontext, $USER->access); + + } else { + $instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder, id ASC'); + $enrols = enrol_get_plugins(true); + // first ask all enabled enrol instances in course if they want to auto enrol user + foreach($instances as $instance) { + if (!isset($enrols[$instance->enrol])) { + continue; + } + $until = $enrols[$instance->enrol]->try_autoenrol($instance); + if ($until !== false) { + $USER->enrol['enrolled'][$course->id] = $until; + $USER->access = remove_temp_roles($coursecontext, $USER->access); + $access = true; + break; + } + } + // if not enrolled yet try to gain temporary guest access + if (!$access) { + foreach($instances as $instance) { + if (!isset($enrols[$instance->enrol])) { + continue; + } + $until = $enrols[$instance->enrol]->try_guestaccess($instance); + if ($until !== false) { + $USER->enrol['tempguest'][$course->id] = $until; + $access = true; + break; + } + } + } + } + } + + if (!$access) { + if ($preventredirect) { + throw new require_login_exception('Not enrolled'); + } + $SESSION->wantsurl = $FULLME; + redirect($CFG->wwwroot .'/enrol/index.php?id='. $course->id); + } + } + + // test visibility + if ($cm && !$cm->visible && !has_capability('moodle/course:viewhiddenactivities', $cmcontext)) { + if ($preventredirect) { + throw new require_login_exception('Activity is hidden'); + } + redirect($CFG->wwwroot, get_string('activityiscurrentlyhidden')); + } + + // groupmembersonly access control if (!empty($CFG->enablegroupmembersonly) and $cm and $cm->groupmembersonly and !has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id))) { if (isguestuser() or !groups_has_membership($cm)) { + if ($preventredirect) { + throw new require_login_exception('Not member of a group'); + } print_error('groupmembersonlyerror', 'group', $CFG->wwwroot.'/course/view.php?id='.$cm->course); } } - // Fetch the course context, and prefetch its child contexts - $coursecontext = get_context_instance(CONTEXT_COURSE, $COURSE->id, MUST_EXIST); - if ($cm) { - $cmcontext = get_context_instance(CONTEXT_MODULE, $cm->id, MUST_EXIST); - } - // Conditional activity access control if (!empty($CFG->enableavailability) and $cm) { + // TODO: this is going to work with login-as-user, sorry! // We cache conditional access in session if (!isset($SESSION->conditionaccessok)) { $SESSION->conditionaccessok = array(); @@ -2299,93 +2470,8 @@ function require_login($courseorid=0, $autologinguest=true, $cm=null, $setwantsu } } - if ($COURSE->id == SITEID) { - /// Eliminate hidden site activities straight away - if ($cm && !$cm->visible && !has_capability('moodle/course:viewhiddenactivities', $cmcontext)) { - redirect($CFG->wwwroot, get_string('activityiscurrentlyhidden')); - } - user_accesstime_log($COURSE->id); /// Access granted, update lastaccess times - return; - - } else { - - /// Check if the user can be in a particular course - if (empty($USER->access['rsw'][$coursecontext->path])) { - // - // MDL-13900 - If the course or the parent category are hidden - // and the user hasn't the 'course:viewhiddencourses' capability, prevent access - // - if ( !($COURSE->visible && course_parent_visible($COURSE)) && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { - echo $OUTPUT->header(); - notice(get_string('coursehidden'), $CFG->wwwroot .'/'); - } - } - - if (is_enrolled($coursecontext) or is_viewing($coursecontext)) { - // Enrolled user or allowed to visit course (managers, inspectors, etc.) - if (session_is_loggedinas()) { // Make sure the REAL person can also access this course - $realuser = session_get_realuser(); - if (!is_enrolled($coursecontext, $realuser->id) and !is_viewing($coursecontext, $realuser->id) and !is_siteadmin($realuser->id)) { - echo $OUTPUT->header(); - notice(get_string('studentnotallowed', '', fullname($USER, true)), $CFG->wwwroot .'/'); - } - } - - // Make sure they can read this activity too, if specified - if ($cm && !$cm->visible && !has_capability('moodle/course:viewhiddenactivities', $cmcontext)) { - redirect($CFG->wwwroot.'/course/view.php?id='.$cm->course, get_string('activityiscurrentlyhidden')); - } - user_accesstime_log($COURSE->id); /// Access granted, update lastaccess times - return; // User is allowed to see this course - - } else { - // guest access - switch ($COURSE->guest) { /// Check course policy about guest access - - case 1: /// Guests always allowed - if ($cm and !$cm->visible) { // Not allowed to see module, send to course page - redirect($CFG->wwwroot.'/course/view.php?id='.$cm->course, - get_string('activityiscurrentlyhidden')); - } - - if ($USER->username != 'guest' and !empty($CFG->guestroleid)) { - // Non-guests who don't currently have access, check if they can be allowed in as a guest - // Temporarily assign them guest role for this context, if it fails later user is asked to enrol - $USER->access = load_temp_role($coursecontext, $CFG->guestroleid, $USER->access); - } - - user_accesstime_log($COURSE->id); /// Access granted, update lastaccess times - return; // User is allowed to see this course - - case 2: /// Guests allowed with key - if (!empty($USER->enrolkey[$COURSE->id])) { // Set by enrol/manual/enrol.php - user_accesstime_log($COURSE->id); /// Access granted, update lastaccess times - return true; - } - // otherwise drop through to logic below (--> enrol.php) - break; - - default: /// Guests not allowed - $strloggedinasguest = get_string('loggedinasguest'); - $PAGE->navbar->add($strloggedinasguest); - echo $OUTPUT->header(); - if (empty($USER->access['rsw'][$coursecontext->path])) { // Normal guest - notice(get_string('guestsnotallowed', '', format_string($COURSE->fullname)), get_login_url()); - } else { - echo $OUTPUT->notification(get_string('guestsnotallowed', '', format_string($COURSE->fullname))); - echo '
'.switchroles_form($COURSE->id).'
'; - echo $OUTPUT->footer(); - exit; - } - break; - } - } - - // Currently not enrolled in the course, so see if they want to enrol - $SESSION->wantsurl = $FULLME; - redirect($CFG->wwwroot .'/course/enrol.php?id='. $COURSE->id); - die; - } + // Finally access granted, update lastaccess times + user_accesstime_log($course->id); } @@ -2425,26 +2511,28 @@ function require_logout() { * @param bool $setwantsurltome Define if we want to set $SESSION->wantsurl, defaults to * true. Used to avoid (=false) some scripts (file.php...) to set that variable, * in order to keep redirects working properly. MDL-14495 + * @param bool $preventredirect set to true in scripts that can not redirect (CLI, rss feeds, etc.), throws exceptions + * @return void */ -function require_course_login($courseorid, $autologinguest=true, $cm=null, $setwantsurltome=true) { +function require_course_login($courseorid, $autologinguest = true, $cm = NULL, $setwantsurltome = true, $preventredirect = false) { global $CFG, $PAGE, $SITE; if (!empty($CFG->forcelogin)) { // login required for both SITE and courses - require_login($courseorid, $autologinguest, $cm, $setwantsurltome); + require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect); } else if (!empty($cm) and !$cm->visible) { // always login for hidden activities - require_login($courseorid, $autologinguest, $cm, $setwantsurltome); + require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect); } else if ((is_object($courseorid) and $courseorid->id == SITEID) or (!is_object($courseorid) and $courseorid == SITEID)) { //login for SITE not required if ($cm and empty($cm->visible)) { // hidden activities are not accessible without login - require_login($courseorid, $autologinguest, $cm, $setwantsurltome); + require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect); } else if ($cm and !empty($CFG->enablegroupmembersonly) and $cm->groupmembersonly) { // not-logged-in users do not have any group membership - require_login($courseorid, $autologinguest, $cm, $setwantsurltome); + require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect); } else { // We still need to instatiate PAGE vars properly so that things // that rely on it like navigation function correctly. @@ -2455,6 +2543,9 @@ function require_course_login($courseorid, $autologinguest=true, $cm=null, $setw $course = clone($SITE); } if ($cm) { + if ($cm->course != $course->id) { + throw new coding_exception('course and cm parameters in require_course_login() call do not match!!'); + } $PAGE->set_cm($cm, $course); $PAGE->set_pagelayout('incourse'); } else { @@ -2472,7 +2563,7 @@ function require_course_login($courseorid, $autologinguest=true, $cm=null, $setw } else { // course login always required - require_login($courseorid, $autologinguest, $cm, $setwantsurltome); + require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect); } } @@ -2754,25 +2845,6 @@ function reset_login_count() { $SESSION->logincount = 0; } -/** - * Sync all meta courses - * Goes through all enrolment records for the courses inside all metacourses and syncs with them. - * @see sync_metacourse() - * - * @global object - */ -function sync_metacourses() { - global $DB; - - if (!$courses = $DB->get_records('course', array('metacourse'=>1))) { - return; - } - - foreach ($courses as $course) { - sync_metacourse($course); - } -} - /** * Returns reference to full info about modules in course (including visibility). * Cached and as fast as possible (0 or 1 db query). @@ -2970,157 +3042,6 @@ function &get_fast_modinfo(&$course, $userid=0) { return $cache[$course->id]; } -/** - * Goes through all enrolment records for the courses inside the metacourse and sync with them. - * - * @todo finish timeend and timestart maybe we could rely on cron - * job to do the cleaning from time to time - * - * @global object - * @global object - * @uses CONTEXT_COURSE - * @param mixed $course the metacourse to synch. Either the course object itself, or the courseid. - * @return bool Success - */ -function sync_metacourse($course) { - global $CFG, $DB; - - // Check the course is valid. - if (!is_object($course)) { - if (!$course = $DB->get_record('course', array('id'=>$course))) { - return false; // invalid course id - } - } - - // Check that we actually have a metacourse. - if (empty($course->metacourse)) { - return false; - } - - // Get a list of roles that should not be synced. - if (!empty($CFG->nonmetacoursesyncroleids)) { - $roleexclusions = 'ra.roleid NOT IN (' . $CFG->nonmetacoursesyncroleids . ') AND'; - } else { - $roleexclusions = ''; - } - - // Get the context of the metacourse. - $context = get_context_instance(CONTEXT_COURSE, $course->id); // SITEID can not be a metacourse - - // We do not ever want to unassign the list of metacourse manager, so get a list of them. - if ($users = get_users_by_capability($context, 'moodle/course:managemetacourse')) { - $managers = array_keys($users); - } else { - $managers = array(); - } - - // Get assignments of a user to a role that exist in a child course, but - // not in the meta coure. That is, get a list of the assignments that need to be made. - if (!$assignments = $DB->get_records_sql(" - SELECT ra.id, ra.roleid, ra.userid - FROM {role_assignments} ra, {context} con, {course_meta} cm - WHERE ra.contextid = con.id AND - con.contextlevel = ".CONTEXT_COURSE." AND - con.instanceid = cm.child_course AND - cm.parent_course = ? AND - $roleexclusions - NOT EXISTS ( - SELECT 1 - FROM {role_assignments} ra2 - WHERE ra2.userid = ra.userid AND - ra2.roleid = ra.roleid AND - ra2.contextid = ? - )", array($course->id, $context->id))) { - $assignments = array(); - } - - // Get assignments of a user to a role that exist in the meta course, but - // not in any child courses. That is, get a list of the unassignments that need to be made. - if (!$unassignments = $DB->get_records_sql(" - SELECT ra.id, ra.roleid, ra.userid - FROM {role_assignments} ra - WHERE ra.contextid = ? AND - $roleexclusions - NOT EXISTS ( - SELECT 1 - FROM {role_assignments} ra2, {context} con2, {course_meta} cm - WHERE ra2.userid = ra.userid AND - ra2.roleid = ra.roleid AND - ra2.contextid = con2.id AND - con2.contextlevel = " . CONTEXT_COURSE . " AND - con2.instanceid = cm.child_course AND - cm.parent_course = ? - )", array($context->id, $course->id))) { - $unassignments = array(); - } - - $success = true; - - // Make the unassignments, if they are not managers. - foreach ($unassignments as $unassignment) { - if (!in_array($unassignment->userid, $managers)) { - $success = role_unassign($unassignment->roleid, $unassignment->userid, 0, $context->id) && $success; - } - } - - // Make the assignments. - foreach ($assignments as $assignment) { - $success = role_assign($assignment->roleid, $assignment->userid, 0, $context->id, 0, 0) && $success; - } - - return $success; - -// TODO: finish timeend and timestart -// maybe we could rely on cron job to do the cleaning from time to time -} - -/** - * Adds a record to the metacourse table and calls sync_metacoures - * - * @global object - * @param int $metacourseid The Metacourse ID for the metacourse to add to - * @param int $courseid The Course ID of the course to add - * @return bool Success - */ -function add_to_metacourse ($metacourseid, $courseid) { - global $DB; - - if (!$metacourse = $DB->get_record("course", array("id"=>$metacourseid))) { - return false; - } - - if (!$course = $DB->get_record("course", array("id"=>$courseid))) { - return false; - } - - if (!$record = $DB->get_record("course_meta", array("parent_course"=>$metacourseid, "child_course"=>$courseid))) { - $rec = new object(); - $rec->parent_course = $metacourseid; - $rec->child_course = $courseid; - $DB->insert_record('course_meta', $rec); - return sync_metacourse($metacourseid); - } - return true; - -} - -/** - * Removes the record from the metacourse table and calls sync_metacourse - * - * @global object - * @param int $metacourseid The Metacourse ID for the metacourse to remove from - * @param int $courseid The Course ID of the course to remove - * @return bool Success - */ -function remove_from_metacourse($metacourseid, $courseid) { - global $DB; - - if ($DB->delete_records('course_meta', array('parent_course'=>$metacourseid, 'child_course'=>$courseid))) { - return sync_metacourse($metacourseid); - } - return false; -} - /** * Determines if the currently logged in user is in editing mode. * Note: originally this function had $userid parameter - it was not usable anyway @@ -3487,12 +3408,10 @@ function truncate_userinfo($info) { * Marks user deleted in internal user database and notifies the auth plugin. * Also unenrols user from all roles and does other cleanup. * - * @todo Decide if this transaction is really needed (look for internal TODO:) + * Any plugin that needs to purge user data should register the 'user_deleted' event. * - * @global object - * @global object - * @param object $user Userobject before delete (without system magic quotes) - * @return boolean success + * @param object $user User object before delete + * @return boolean always true */ function delete_user($user) { global $CFG, $DB; @@ -3500,12 +3419,8 @@ function delete_user($user) { require_once($CFG->libdir.'/gradelib.php'); require_once($CFG->dirroot.'/message/lib.php'); - // delete all grades - backup is kept in grade_grades_history table - if ($grades = grade_grade::fetch_all(array('userid'=>$user->id))) { - foreach ($grades as $grade) { - $grade->delete('userdelete'); - } - } + // delete all grades - backup is kept in grade_grades_history table + grade_user_delete($user->id); //move unread messages from this user to read message_move_userfrom_unread2read($user->id); @@ -3516,10 +3431,19 @@ function delete_user($user) { // remove from all groups $DB->delete_records('groups_members', array('userid'=>$user->id)); - // unenrol from all roles in all contexts - role_unassign(0, $user->id); // this might be slow but it is really needed - modules might do some extra cleanup! + // brute force unenrol from all courses + $DB->delete_records('user_enrolments', array('userid'=>$user->id)); - // now do a final accesslib cleanup - removes all role assignments in user context and context itself + // purge user preferences + $DB->delete_records('user_preferences', array('userid'=>$user->id)); + + // purge user extra profile info + $DB->delete_records('user_info_data', array('userid'=>$user->id)); + + // last course access not necessary either + $DB->delete_records('user_lastaccess', array('userid'=>$user->id)); + + // final accesslib cleanup - removes all role assignments in user context and context itself delete_context(CONTEXT_USER, $user->id); require_once($CFG->dirroot.'/tag/lib.php'); @@ -3546,6 +3470,7 @@ function delete_user($user) { $authplugin = get_auth_plugin($user->auth); $authplugin->user_delete($user); + // any plugin that needs to cleanup should register this event events_trigger('user_deleted', $user); return true; @@ -4129,26 +4054,6 @@ function remove_course_contents($courseid, $showfeedback=true) { $DB->delete_records($table, array($col=>$course->id)); } - -/// Clean up metacourse stuff - - if ($course->metacourse) { - $DB->delete_records("course_meta", array("parent_course"=>$course->id)); - sync_metacourse($course->id); // have to do it here so the enrolments get nuked. sync_metacourses won't find it without the id. - if ($showfeedback) { - echo $OUTPUT->notification("$strdeleted course_meta"); - } - } else { - if ($parents = $DB->get_records("course_meta", array("child_course"=>$course->id))) { - foreach ($parents as $parent) { - remove_from_metacourse($parent->parent_course,$parent->child_course); // this will do the unenrolments as well. - } - if ($showfeedback) { - echo $OUTPUT->notification("$strdeleted course_meta"); - } - } - } - /// Delete questions and question categories question_delete_course($course, $showfeedback); @@ -4280,7 +4185,7 @@ function reset_course_userdata($data) { if (!empty($data->reset_roles_local)) { $children = get_child_contexts($context); foreach ($children as $child) { - role_unassign(0, 0, 0, $child->id); + role_unassign_all(array('contextid'=>$child->id)); } //force refresh for logged in users mark_context_dirty($context->path); @@ -4289,20 +4194,40 @@ function reset_course_userdata($data) { // First unenrol users - this cleans some of related user data too, such as forum subscriptions, tracking, etc. $data->unenrolled = array(); - if (!empty($data->reset_roles)) { - foreach($data->reset_roles as $roleid) { - if ($users = get_role_users($roleid, $context, false, 'u.id', 'u.id ASC')) { - foreach ($users as $user) { - role_unassign($roleid, $user->id, 0, $context->id); - if (!is_enrolled($context, $user->id)) { - $data->unenrolled[$user->id] = $user->id; - } + if (!empty($data->unenrol_users)) { + $plugins = enrol_get_plugins(true); + $instances = enrol_get_instances($data->courseid, true); + foreach ($instances as $key=>$instance) { + if (!isset($plugins[$instance->enrol])) { + unset($instances[$key]); + continue; + } + if (!$plugins[$instance->enrol]->allow_unenrol($instance)) { + unset($instances[$key]); + } + } + + $sqlempty = $DB->sql_empty(); + foreach($data->unenrol_users as $withroleid) { + $sql = "SELECT DISTINCT ue.userid, ue.enrolid + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid) + JOIN {context} c ON (c.contextlevel = :courselevel AND c.instanceid = e.courseid) + JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.roleid = :roleid AND ra.userid = ue.userid)"; + $params = array('courseid'=>$data->courseid, 'roleid'=>$withroleid, 'courselevel'=>CONTEXT_COURSE); + + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $ue) { + if (!isset($instances[$ue->enrolid])) { + continue; } + $plugins[$instances[$ue->enrolid]->enrol]->unenrol_user($instances[$ue->enrolid], $ue->userid); + $data->unenrolled[$ue->userid] = $ue->userid; } } } if (!empty($data->unenrolled)) { - $status[] = array('component'=>$componentstr, 'item'=>get_string('unenrol').' ('.count($data->unenrolled).')', 'error'=>false); + $status[] = array('component'=>$componentstr, 'item'=>get_string('unenrol', 'enrol').' ('.count($data->unenrolled).')', 'error'=>false); } @@ -5048,58 +4973,6 @@ function email_is_not_allowed($email) { return false; } -/** - * Send welcome email to specified user - * - * @global object - * @global object - * @param object $course - * @param user $user A {@link $USER} object - * @return bool - */ -function email_welcome_message_to_user($course, $user=NULL) { - global $CFG, $USER; - - if (isset($CFG->sendcoursewelcomemessage) and !$CFG->sendcoursewelcomemessage) { - return; - } - - if (empty($user)) { - if (!isloggedin()) { - return false; - } - $user = $USER; - } - - if (!empty($course->welcomemessage)) { - $message = $course->welcomemessage; - } else { - $a = new object(); - $a->coursename = $course->fullname; - if ($course->id == SITEID) { - $a->profileurl = "$CFG->wwwroot/user/profile.php?id=$user->id"; - } else { - $a->profileurl = "$CFG->wwwroot/user/view.php?id=$user->id&course=$course->id"; - } - $message = get_string("welcometocoursetext", "", $a); - } - - /// If you don't want a welcome message sent, then make the message string blank. - if (!empty($message)) { - $subject = get_string('welcometocourse', '', format_string($course->fullname)); - - $context = get_context_instance(CONTEXT_COURSE, $course->id); - // TODO: replace with $CFG->coursemanager test, 'moodle/course:update' is very wrong!! - if ($users = get_users_by_capability($context, 'moodle/course:update', 'u.*', 'u.id ASC','', '', '', '', false, true)) { - $users = sort_by_roleassignment_authority($users, $context); - $teacher = array_shift($users); - } else { - $teacher = get_admin(); - } - email_to_user($user, $teacher, $subject, $message); - } -} - /// FILE HANDLING ///////////////////////////////////////////// /** @@ -7013,6 +6886,7 @@ function get_core_subsystems() { 'dock' => NULL, 'editor' => 'lib/editor', 'edufields' => NULL, + 'enrol' => 'enrol', 'error' => NULL, 'filepicker' => NULL, 'filters' => NULL, @@ -9338,24 +9212,7 @@ function is_mnet_remote_user($user) { } /** - * Checks if a given plugin is in the list of enabled enrolment plugins. - * - * @global object - * @param string $auth Enrolment plugin. - * @return boolean Whether the plugin is enabled. - */ -function is_enabled_enrol($enrol='') { - global $CFG; - - // use the global default if not specified - if ($enrol == '') { - $enrol = $CFG->enrol; - } - return in_array($enrol, explode(',', $CFG->enrol_plugins_enabled)); -} - -/** - * This function will search for browser preferred languages, setting Moodle + * This function will search for browser prefereed languages, setting Moodle * to use the best one available if $SESSION->lang is undefined * * @global object @@ -9569,7 +9426,7 @@ function is_primary_admin($userid){ } } - /** +/** * Returns the site identifier * * @global object diff --git a/lib/navigationlib.php b/lib/navigationlib.php index fceab8eee9d..09549e848ef 100644 --- a/lib/navigationlib.php +++ b/lib/navigationlib.php @@ -26,11 +26,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -if (!function_exists('get_all_sections')) { - /** Include course lib for its functions */ - require_once($CFG->dirroot.'/course/lib.php'); -} - /** * The name that will be used to separate the navigation cache within SESSION */ @@ -933,7 +928,7 @@ class global_navigation extends navigation_node { $CFG->navshowcategories = false; } - $this->mycourses = get_my_courses($USER->id, 'visible DESC,sortorder ASC', null, false, $limit); + $this->mycourses = enrol_get_my_courses(NULL, 'visible DESC,sortorder ASC', $limit); $showallcourses = (count($this->mycourses) == 0 || !empty($CFG->navshowallcourses)); $showcategories = ($showallcourses && !empty($CFG->navshowcategories)); @@ -1298,7 +1293,9 @@ class global_navigation extends navigation_node { * @return array An array of course section nodes */ public function load_generic_course_sections(stdClass $course, navigation_node $coursenode, $courseformat='unknown') { - global $DB, $USER; + global $CFG, $DB, $USER; + + require_once($CFG->dirroot.'/course/lib.php'); $modinfo = get_fast_modinfo($course); $sections = array_slice(get_all_sections($course->id), 0, $course->numsections+1, true); @@ -1654,7 +1651,7 @@ class global_navigation extends navigation_node { public function add_course(stdClass $course, $forcegeneric = false) { global $CFG; $canviewhidden = has_capability('moodle/course:viewhiddencourses', $this->page->context); - if ($course->id !== SITEID && !$canviewhidden && (!$course->visible || !course_parent_visible($course))) { + if ($course->id !== SITEID && !$canviewhidden && !$course->visible) { return false; } @@ -2574,12 +2571,8 @@ class settings_navigation extends navigation_node { $course = $this->page->course; $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); - if (!$this->cache->cached('canviewcourse'.$course->id)) { - $this->cache->{'canviewcourse'.$course->id} = has_capability('moodle/course:participate', $coursecontext); - } - if ($course->id === SITEID || !$this->cache->{'canviewcourse'.$course->id}) { - return false; - } + + // note: do not test if enrolled or viewing here because we need the enrol link in Course administration section $coursenode = $this->add(get_string('courseadministration'), null, self::TYPE_COURSE, null, 'courseadmin'); if ($forceopen) { @@ -2614,25 +2607,13 @@ class settings_navigation extends navigation_node { } } - if (has_capability('moodle/role:assign', $coursecontext)) { - // Add assign or override roles if allowed - $url = new moodle_url('/'.$CFG->admin.'/roles/assign.php', array('contextid'=>$coursecontext->id)); - $coursenode->add(get_string('assignroles', 'role'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/roles', '')); - // Override roles - if (has_capability('moodle/role:review', $coursecontext) or count(get_overridable_roles($coursecontext))>0) { - $url = new moodle_url('/'.$CFG->admin.'/roles/permissions.php', array('contextid'=>$coursecontext->id)); - $coursenode->add(get_string('permissions', 'role'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/permissions', '')); - } - // Check role permissions - if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride','moodle/role:override', 'moodle/role:assign'), $coursecontext)) { - $url = new moodle_url('/'.$CFG->admin.'/roles/check.php', array('contextid'=>$coursecontext->id)); - $coursenode->add(get_string('checkpermissions', 'role'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/checkpermissions', '')); - } - // Manage filters - if (has_capability('moodle/filter:manage', $coursecontext) && count(filter_get_available_in_context($coursecontext))>0) { - $url = new moodle_url('/filter/manage.php', array('contextid'=>$coursecontext->id)); - $coursenode->add(get_string('filters', 'admin'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/filter', '')); - } + // add enrol nodes + enrol_add_course_navigation($coursenode, $course); + + // Manage filters + if (has_capability('moodle/filter:manage', $coursecontext) && count(filter_get_available_in_context($coursecontext))>0) { + $url = new moodle_url('/filter/manage.php', array('contextid'=>$coursecontext->id)); + $coursenode->add(get_string('filters', 'admin'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/filter', '')); } // Add view grade report is permitted @@ -2663,23 +2644,6 @@ class settings_navigation extends navigation_node { $coursenode->add(get_string('outcomes', 'grades'), $url, self::TYPE_SETTING, null, 'outcomes', new pix_icon('i/outcomes', '')); } - // Add meta course links - if ($course->metacourse) { - if (has_capability('moodle/course:managemetacourse', $coursecontext)) { - $url = new moodle_url('/course/importstudents.php', array('id'=>$course->id)); - $coursenode->add(get_string('childcourses'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/course', '')); - } else if (has_capability('moodle/role:assign', $coursecontext)) { - $roleassign = $coursenode->add(get_string('childcourses'), null, self::TYPE_SETTING, null, null, new pix_icon('i/course', '')); - $roleassign->hidden = true; - } - } - - // Manage groups in this course - if (($course->groupmode || !$course->groupmodeforce) && has_capability('moodle/course:managegroups', $coursecontext)) { - $url = new moodle_url('/group/index.php', array('id'=>$course->id)); - $coursenode->add(get_string('groups'), $url, self::TYPE_SETTING, null, 'groups', new pix_icon('i/group', '')); - } - // Backup this course if (has_capability('moodle/backup:backupcourse', $coursecontext)) { $url = new moodle_url('/backup/backup.php', array('id'=>$course->id)); @@ -2730,37 +2694,6 @@ class settings_navigation extends navigation_node { $coursenode->add(get_string('files'), $url, self::TYPE_SETTING, null, 'coursefiles', new pix_icon('i/files', '')); } - // Authorize hooks - if ($course->enrol == 'authorize' || (empty($course->enrol) && $CFG->enrol == 'authorize')) { - require_once($CFG->dirroot.'/enrol/authorize/const.php'); - $url = new moodle_url('/enrol/authorize/index.php', array('course'=>$course->id)); - $coursenode->add(get_string('payments'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/payment', '')); - if (has_capability('enrol/authorize:managepayments', $this->page->context)) { - $cnt = $DB->count_records('enrol_authorize', array('status'=>AN_STATUS_AUTH, 'courseid'=>$course->id)); - if ($cnt) { - $url = new moodle_url('/enrol/authorize/index.php', array('course'=>$course->id,'status'=>AN_STATUS_AUTH)); - $coursenode->add(get_string('paymentpending', 'moodle', $cnt), $url, self::TYPE_SETTING, null, null, new pix_icon('i/payment', '')); - } - } - } - - // Unenrol link - if (empty($course->metacourse) && ($course->id!==SITEID)) { - if (is_enrolled(get_context_instance(CONTEXT_COURSE, $course->id))) { - if (has_capability('moodle/role:unassignself', $this->page->context, NULL, false) and get_user_roles($this->page->context, $USER->id, false)) { // Have some role - $this->content->items[]=''.get_string('unenrolme', '', format_string($course->shortname)).''; - $this->content->icons[]=''; - } - - } else if (is_viewing(get_context_instance(CONTEXT_COURSE, $course->id))) { - // inspector, manager, etc. - do not show anything - } else { - // access because otherwise they would not get into this course at all - $this->content->items[]=''.get_string('enrolme', '', format_string($course->shortname)).''; - $this->content->icons[]=''; - } - } - // Switch roles $roles = array(); $assumedrole = $this->in_alternative_role(); @@ -2802,6 +2735,10 @@ class settings_navigation extends navigation_node { * @param stdClass $course */ protected function add_course_editing_links($course) { + global $CFG; + + require_once($CFG->dirroot.'/course/lib.php'); + // Add `add` resources|activities branches $structurefile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php'; if (file_exists($structurefile)) { @@ -3065,12 +3002,12 @@ class settings_navigation extends navigation_node { // Check that the user can view the profile $usercontext = get_context_instance(CONTEXT_USER, $user->id); // User context if ($course->id==SITEID) { - if ($CFG->forceloginforprofiles && !!has_coursemanager_role($user->id) && !has_capability('moodle/user:viewdetails', $usercontext)) { // Reduce possibility of "browsing" userbase at site level + if ($CFG->forceloginforprofiles && !!has_coursecontact_role($user->id) && !has_capability('moodle/user:viewdetails', $usercontext)) { // Reduce possibility of "browsing" userbase at site level // Teachers can browse and be browsed at site level. If not forceloginforprofiles, allow access (bug #4366) return false; } } else { - if ((!has_capability('moodle/user:viewdetails', $coursecontext) && !has_capability('moodle/user:viewdetails', $usercontext)) || !has_capability('moodle/course:participate', $coursecontext, $user->id, false)) { + if ((!has_capability('moodle/user:viewdetails', $coursecontext) && !has_capability('moodle/user:viewdetails', $usercontext)) || !is_enrolled($coursecontext, $user->id)) { return false; } if (groups_get_course_groupmode($course) == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $coursecontext)) { @@ -3356,32 +3293,13 @@ class settings_navigation extends navigation_node { $frontpage->add(get_string('settings'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/settings', '')); } - //Participants - if (has_capability('moodle/site:viewparticipants', $coursecontext)) { - $url = new moodle_url('/user/index.php', array('contextid'=>$coursecontext->id)); - $frontpage->add(get_string('participants'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/users', '')); - } + // add enrol nodes + enrol_add_course_navigation($frontpage, $course); - // Roles - if (has_capability('moodle/role:assign', $coursecontext)) { - // Add assign or override roles if allowed - $url = new moodle_url('/'.$CFG->admin.'/roles/assign.php', array('contextid'=>$coursecontext->id)); - $frontpage->add(get_string('assignroles', 'role'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/roles', '')); - // Override roles - if (has_capability('moodle/role:review', $coursecontext) or count(get_overridable_roles($coursecontext))>0) { - $url = new moodle_url('/'.$CFG->admin.'/roles/permissions.php', array('contextid'=>$coursecontext->id)); - $frontpage->add(get_string('permissions', 'role'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/permissions', '')); - } - // Check role permissions - if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride','moodle/role:override', 'moodle/role:assign'), $coursecontext)) { - $url = new moodle_url('/'.$CFG->admin.'/roles/check.php', array('contextid'=>$coursecontext->id)); - $frontpage->add(get_string('checkpermissions', 'role'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/checkpermissions', '')); - } - // Manage filters - if (has_capability('moodle/filter:manage', $coursecontext) && count(filter_get_available_in_context($coursecontext))>0) { - $url = new moodle_url('/filter/manage.php', array('contextid'=>$coursecontext->id)); - $frontpage->add(get_string('filters', 'admin'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/filter', '')); - } + // Manage filters + if (has_capability('moodle/filter:manage', $coursecontext) && count(filter_get_available_in_context($coursecontext))>0) { + $url = new moodle_url('/filter/manage.php', array('contextid'=>$coursecontext->id)); + $frontpage->add(get_string('filters', 'admin'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/filter', '')); } // Backup this course diff --git a/lib/outputrequirementslib.php b/lib/outputrequirementslib.php index 49c9873ff8c..0dd9942c0f8 100644 --- a/lib/outputrequirementslib.php +++ b/lib/outputrequirementslib.php @@ -378,7 +378,7 @@ class page_requirements_manager { array('saving', 'repository'), array('search', 'repository'), array('searching', 'repository'), array('size', 'repository'), array('submit', 'repository'), array('sync', 'repository'), array('title', 'repository'), array('upload', 'repository'), array('uploading', 'repository'), array('xhtmlerror', 'repository'), - array('xhtml', 'quiz'), array('cancel'), array('chooselicense', 'repository'), array('author', 'repository'), + array('xhtml', 'quiz'), array('chooselicense', 'repository'), array('author', 'repository'), array('ok', 'moodle'), array('error', 'moodle'), array('info', 'moodle') )); break; @@ -702,9 +702,9 @@ class page_requirements_manager { if (!$component) { throw new coding_exception('The $module parameter is required for page_requirements_manager::string_for_js.'); } - if (isset($this->stringsforjs[$component][$identifier]) && $this->stringsforjs[$component][$identifier] != $string) { + if (isset($this->stringsforjs[$component][$identifier]) && $this->stringsforjs[$component][$identifier] !== $string) { throw new coding_exception("Attempt to re-define already required string '$identifier' " . - "from lang file '$component'. Did you already ask for it with a different \$a?"); + "from lang file '$component'. Did you already ask for it with a different \$a? {$this->stringsforjs[$component][$identifier]} !== $string"); } $this->stringsforjs[$component][$identifier] = $string; } diff --git a/lib/sessionlib.php b/lib/sessionlib.php index e6b87f08eb5..baa10e4da8f 100644 --- a/lib/sessionlib.php +++ b/lib/sessionlib.php @@ -74,7 +74,7 @@ interface moodle_session { * @return void */ public function write_close(); - + /** * Check for existing session with id $sid * @param unknown_type $sid @@ -159,7 +159,7 @@ abstract class session_stub implements moodle_session { } catch (Exception $ignored) { // probably install/upgrade - ignore this problem } - + if (NO_MOODLE_COOKIES) { return; } @@ -372,7 +372,7 @@ class legacy_file_session extends session_stub { $sessionfile = clean_param("$CFG->dataroot/sessions/sess_$sid", PARAM_FILE); return file_exists($sessionfile); } - + } @@ -401,20 +401,20 @@ class database_session extends session_stub { } } } - + public function session_exists($sid){ global $CFG; try { $sql = "SELECT * FROM {sessions} WHERE timemodified < ? AND sid=? AND state=?"; $params = array(time() + $CFG->sessiontimeout, $sid, 0); - + return $this->database->record_exists_sql($sql, $params); } catch (dml_exception $ex) { error_log('Error checking existance of database session'); return false; } } - + protected function init_session_storage() { global $CFG; @@ -878,7 +878,7 @@ function session_set_user($user) { unset($_SESSION['USER']->description); // conserve memory if (!isset($_SESSION['USER']->access)) { // check enrolments and load caps only once - check_enrolment_plugins($_SESSION['USER']); + enrol_check_plugins($_SESSION['USER']); load_all_capabilities(); } sesskey(); // init session key diff --git a/lib/setup.php b/lib/setup.php index 5546ae30503..8d735d6c617 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -330,6 +330,7 @@ require_once($CFG->libdir .'/datalib.php'); // Legacy lib with a big-mix require_once($CFG->libdir .'/accesslib.php'); // Access control functions require_once($CFG->libdir .'/deprecatedlib.php'); // Deprecated functions included for backward compatibility require_once($CFG->libdir .'/moodlelib.php'); // Other general-purpose functions +require_once($CFG->libdir .'/enrollib.php'); // Enrolment related functions require_once($CFG->libdir .'/pagelib.php'); // Library that defines the moodle_page class, used for $PAGE require_once($CFG->libdir .'/blocklib.php'); // Library for controlling blocks require_once($CFG->libdir .'/eventslib.php'); // Events functions diff --git a/lib/setuplib.php b/lib/setuplib.php index 34cb14d96c9..1bc9d3fdc11 100644 --- a/lib/setuplib.php +++ b/lib/setuplib.php @@ -95,6 +95,17 @@ class moodle_exception extends Exception { } } +/** + * Course/activity access exception. + * + * This exception is thrown from require_login() + */ +class require_login_exception extends moodle_exception { + function __construct($debuginfo) { + parent::__construct('requireloginerror', 'error', '', NULL, $debuginfo); + } +} + /** * Web service parameter exception class * @@ -789,7 +800,7 @@ function get_real_size($size=0) { */ function redirect_if_major_upgrade_required() { global $CFG; - $lastmajordbchanges = 2010052700; + $lastmajordbchanges = 2010061600; if (empty($CFG->version) or (int)$CFG->version < $lastmajordbchanges or during_initial_install() or !empty($CFG->adminsetuppending)) { try { diff --git a/lib/simpletest/broken_testfilelib.php b/lib/simpletest/broken_testfilelib.php index d0361c0fdad..ea25b91cd54 100644 --- a/lib/simpletest/broken_testfilelib.php +++ b/lib/simpletest/broken_testfilelib.php @@ -135,7 +135,7 @@ class filelib_test extends UnitTestCaseUsingDatabase { $this->user->id = create_user($this->user); // Assign user to course - // role_assign(5, $this->user->id, 0, get_context_instance(CONTEXT_COURSE, $this->course->id)->id); + // role_assign(5, $this->user->id, get_context_instance(CONTEXT_COURSE, $this->course->id)->id); // Create a module $module = new stdClass(); diff --git a/lib/simpletest/testaccesslib.php b/lib/simpletest/testaccesslib.php index ab943274930..eacfc0dce20 100644 --- a/lib/simpletest/testaccesslib.php +++ b/lib/simpletest/testaccesslib.php @@ -261,10 +261,6 @@ class accesslib_test extends UnitTestCaseUsingDatabase { $context = $contexts['cou']; $context->id = SYSCONTEXTID + 2; - $this->load_test_data('capabilities', - array('name'), array( - array('moodle/course:participate'))); - $roles = $this->load_test_data('role', array( 'name', 'shortname', 'description', 'sortorder'), array( 'admin' => array('admin', 'admin', 'not null', 1), @@ -274,13 +270,7 @@ class accesslib_test extends UnitTestCaseUsingDatabase { $adminid = $roles['admin']->id; $r1id = $roles['r1']->id; $r2id = $roles['r2']->id; - $funnyid = $roles['funny']->id; // strange role to test that roles with 'moodle/course:participate' are not returned. - - $this->load_test_data('role_capabilities', - array('roleid', 'capability', 'contextid', 'permission'), array( - array( $r1id, 'moodle/course:participate', SYSCONTEXTID + 1, CAP_ALLOW), - array( $r2id, 'moodle/course:participate', SYSCONTEXTID, CAP_ALLOW), - array($funnyid, 'moodle/course:participate', SYSCONTEXTID, CAP_ALLOW))); + $funnyid = $roles['funny']->id; // strange role $this->load_test_data('role_assignments', array('userid', 'contextid', 'roleid'), array( @@ -295,13 +285,6 @@ class accesslib_test extends UnitTestCaseUsingDatabase { array( $r2id , $r2id), array( $r2id , $funnyid))); - // Admin should be able to switch to any role with 'moodle/course:participate' in any context. - $this->switch_global_user_id(1); - accesslib_clear_all_caches_for_unit_testing(); - $this->assert(new ArraysHaveSameValuesExpectation(array($r2id)), array_keys(get_switchable_roles($syscontext))); - $this->assert(new ArraysHaveSameValuesExpectation(array($r2id)), array_keys(get_switchable_roles($context))); - $this->revert_global_user_id(); - // r1 should be able to switch to r2, but this user only has r1 in $context, not $syscontext. $this->switch_global_user_id(2); accesslib_clear_all_caches_for_unit_testing(); @@ -316,21 +299,5 @@ class accesslib_test extends UnitTestCaseUsingDatabase { $this->assert(new ArraysHaveSameValuesExpectation(array($r2id)), array_keys(get_switchable_roles($context))); } - function test_get_allowed_switchable_roles() { - $this->create_test_table('role_capabilities', 'lib'); - - $this->load_test_data('role_capabilities', - array('roleid', 'capability', 'contextid', 'permission'), array( - array( 1, 'moodle/forum:replypost', SYSCONTEXTID, CAP_ALLOW), - array( 2, 'moodle/course:participate', SYSCONTEXTID, CAP_ALLOW), - array( 4, 'moodle/course:participate', SYSCONTEXTID, CAP_ALLOW), - array( 5, 'moodle/course:participate', SYSCONTEXTID, CAP_ALLOW), - array( 6, 'moodle/course:participate', SYSCONTEXTID, CAP_PREVENT), - )); - - $this->switch_to_test_db(); - - $this->assert(new ArraysHaveSameValuesExpectation(array(2, 5)), array_keys(get_allowed_switchable_roles())); - } } diff --git a/lib/upgradelib.php b/lib/upgradelib.php index a44bb93b49f..d388203ab19 100644 --- a/lib/upgradelib.php +++ b/lib/upgradelib.php @@ -1191,11 +1191,11 @@ function install_core($version, $verbose) { // store version upgrade_main_savepoint(true, $version, false); - // Continue with the instalation + // Continue with the installation events_update_definition('moodle'); message_update_providers('moodle'); - // Write default settings unconditionlly + // Write default settings unconditionally admin_apply_default_settings(NULL, true); print_upgrade_part_end(null, true, $verbose); @@ -1253,6 +1253,8 @@ function upgrade_core($version, $verbose) { // Reset caches again, just to be sure upgrade_reset_caches(); remove_dir($CFG->dataroot . '/cache', true); // flush cache + $syscontext = get_context_instance(CONTEXT_SYSTEM); + mark_context_dirty($syscontext->path); print_upgrade_part_end('moodle', false, $verbose); } catch (Exception $ex) { diff --git a/message/lib.php b/message/lib.php index 20df4e2d164..267500bf497 100644 --- a/message/lib.php +++ b/message/lib.php @@ -319,7 +319,7 @@ function message_print_search_results($frm) { if (optional_param('mycourses', 0, PARAM_BOOL)) { $users = array(); - $mycourses = get_my_courses($USER->id); + $mycourses = enrol_get_my_courses(); foreach ($mycourses as $mycourse) { if (is_array($susers = message_search_users($mycourse->id, $frm->name))) { foreach ($susers as $suser) $users[$suser->id] = $suser; diff --git a/mod/assignment/db/events.php b/mod/assignment/db/events.php new file mode 100644 index 00000000000..7234b30e430 --- /dev/null +++ b/mod/assignment/db/events.php @@ -0,0 +1,36 @@ +box_start('generalbox', 'notice'); echo '

'. get_string('noguestchoose', 'choice') .'

'; echo $OUTPUT->container_start('continuebutton'); - echo $OUTPUT->single_button(new moodle_url('/course/enrol.php?', array('id'=>$course->id)), get_string('enrolme', '', format_string($course->shortname))); + echo $OUTPUT->single_button(new moodle_url('/enrol/index.php?', array('id'=>$course->id)), get_string('enrolme', 'core_enrol', format_string($course->shortname))); echo $OUTPUT->container_end(); echo $OUTPUT->box_end(); diff --git a/mod/feedback/show_entries.php b/mod/feedback/show_entries.php index 9e4d74dab13..220070a540a 100644 --- a/mod/feedback/show_entries.php +++ b/mod/feedback/show_entries.php @@ -95,7 +95,7 @@ if($do_show == 'showentries'){ } else { $groupmode = $course->groupmode; } - + // $groupselect = groups_print_activity_menu($cm, $CFG->wwwroot . '/mod/feedback/show_entries.php?id=' . $cm->id.'&do_show=showentries', true); $groupselect = groups_print_activity_menu($cm, $url->out(), true); $mygroupid = groups_get_activity_group($cm); @@ -103,15 +103,15 @@ if($do_show == 'showentries'){ // preparing the table for output $baseurl = new moodle_url('/mod/feedback/show_entries.php'); $baseurl->params(array('id'=>$id, 'do_show'=>$do_show, 'showall'=>$showall)); - + $tablecolumns = array('userpic', 'fullname', 'timemodified'); $tableheaders = array(get_string('userpic'), get_string('fullnameuser'), get_string('date')); - + if(has_capability('mod/feedback:deletesubmissions', $context)) { $tablecolumns[] = 'deleteentry'; $tableheaders[] = ''; } - + $table = new flexible_table('feedback-showentry-list-'.$course->id); $table->define_columns($tablecolumns); @@ -153,10 +153,10 @@ if($do_show == 'showentries'){ }else { $usedgroupid = false; } - + $matchcount = feedback_count_complete_users($cm, $usedgroupid); $table->initialbars(true); - + if($showall) { $startpage = false; $pagecount = false; @@ -165,7 +165,7 @@ if($do_show == 'showentries'){ $startpage = $table->get_page_start(); $pagecount = $table->get_page_size(); } - + $students = feedback_get_complete_users($cm, $usedgroupid, $where, $sort, $startpage, $pagecount); $completedFeedbackCount = feedback_get_completeds_group_count($feedback, $mygroupid); @@ -193,7 +193,7 @@ if($do_show == 'showentries'){ // echo '
'; if (!$students) { if($courseid != SITEID){ - echo $OUTPUT->notification(get_string('noexistingstudents')); + echo $OUTPUT->notification(get_string('noexistingparticipants', 'enrol')); } } else{ echo print_string('non_anonymous_entries', 'feedback'); @@ -202,17 +202,17 @@ if($do_show == 'showentries'){ foreach ($students as $student){ $completedCount = $DB->count_records('feedback_completed', array('userid'=>$student->id, 'feedback'=>$feedback->id, 'anonymous_response'=>FEEDBACK_ANONYMOUS_NO)); if($completedCount > 0) { - + //userpicture and link to the profilepage $profilelink = ''.fullname($student).''; $data = array ($OUTPUT->user_picture($student, array('courseid'=>$course->id)), $profilelink); - + //link to the entry of the user $feedbackcompleted = $DB->get_record('feedback_completed', array('feedback'=>$feedback->id, ' userid'=>$student->id, 'anonymous_response'=>FEEDBACK_ANONYMOUS_NO)); $showentryurl = new moodle_url($url, array('userid'=>$student->id, 'do_show'=>'showoneentry')); $showentrylink = ''.UserDate($feedbackcompleted->timemodified).''; $data[] = $showentrylink; - + //link to delete the entry if(has_capability('mod/feedback:deletesubmissions', $context)) { $deleteentryurl = new moodle_url($CFG->wwwroot.'/mod/feedback/delete_completed.php', array('id'=>$cm->id, 'completedid'=>$feedbackcompleted->id, 'do_show'=>'showoneentry')); @@ -223,9 +223,9 @@ if($do_show == 'showentries'){ } } $table->print_html(); - + $allurl = new moodle_url($baseurl); - + if ($showall) { $allurl->param('showall', 0); echo $OUTPUT->container(html_writer::link($allurl, get_string('showperpage', '', FEEDBACK_DEFAULT_PAGE_COUNT)), array(), 'showall'); @@ -265,13 +265,13 @@ if($do_show == 'showoneentry') { if(is_array($feedbackitems)){ $align = right_to_left() ? 'right' : 'left'; $usr = $DB->get_record('user', array('id'=>$userid)); - + if($feedbackcompleted) { echo $OUTPUT->heading(UserDate($feedbackcompleted->timemodified).' ('.fullname($usr).')', 3); } else { echo $OUTPUT->heading(get_string('not_completed_yet','feedback'), 3); } - + echo $OUTPUT->box_start('feedback_items'); $itemnr = 0; foreach($feedbackitems as $feedbackitem){ diff --git a/mod/feedback/show_nonrespondents.php b/mod/feedback/show_nonrespondents.php index b90b412a21b..2600208ca01 100644 --- a/mod/feedback/show_nonrespondents.php +++ b/mod/feedback/show_nonrespondents.php @@ -46,7 +46,7 @@ if($feedback->anonymous != FEEDBACK_ANONYMOUS_NO OR $feedback->course == SITEID) { print_error('error'); } - + $url = new moodle_url('/mod/feedback/show_nonrespondents.php', array('id'=>$cm->id)); $PAGE->set_url($url); @@ -54,7 +54,7 @@ if (!$context = get_context_instance(CONTEXT_MODULE, $cm->id)) { print_error('badcontext'); } - + //we need the coursecontext to allow sending of mass mails if (!$coursecontext = get_context_instance(CONTEXT_COURSE, $course->id)) { print_error('badcontext'); @@ -125,22 +125,22 @@ } else { $groupmode = $course->groupmode; } - + $groupselect = groups_print_activity_menu($cm, $url->out(), true); $mygroupid = groups_get_activity_group($cm); // preparing the table for output $baseurl = new moodle_url('/mod/feedback/show_nonrespondents.php'); $baseurl->params(array('id'=>$id, 'showall'=>$showall)); - + $tablecolumns = array('userpic', 'fullname', 'status'); $tableheaders = array(get_string('userpic'), get_string('fullnameuser'), get_string('status')); - + if(has_capability('moodle/course:bulkmessaging', $coursecontext)) { $tablecolumns[] = 'select'; $tableheaders[] = get_string('select'); } - + $table = new flexible_table('feedback-shownonrespondents-'.$course->id); $table->define_columns($tablecolumns); @@ -157,7 +157,7 @@ TABLE_VAR_ILAST => 'silast', TABLE_VAR_PAGE => 'spage' )); - + $table->no_sorting('select'); $table->no_sorting('status'); @@ -186,10 +186,10 @@ }else { $usedgroupid = false; } - + $matchcount = feedback_count_incomplete_users($cm, $usedgroupid); $table->initialbars(false); - + if($showall) { $startpage = false; $pagecount = false; @@ -198,7 +198,7 @@ $startpage = $table->get_page_start(); $pagecount = $table->get_page_size(); } - + $students = feedback_get_incomplete_users($cm, $usedgroupid, $sort, $startpage, $pagecount); //####### viewreports-start //print the list of students @@ -208,7 +208,7 @@ echo $OUTPUT->box_start('mdl-align'); // echo '
'; if (!$students) { - echo $OUTPUT->notification(get_string('noexistingstudents')); + echo $OUTPUT->notification(get_string('noexistingparticipants', 'enrol')); } else{ echo print_string('non_respondents_students', 'feedback'); echo ' ('.$matchcount.')
'; @@ -221,13 +221,13 @@ //userpicture and link to the profilepage $profilelink = ''.fullname($user).''; $data = array ($OUTPUT->user_picture($user, array('courseid'=>$course->id)), $profilelink); - + if($DB->record_exists('feedback_completedtmp', array('userid'=>$user->id))) { $data[] = get_string('started', 'feedback'); }else { $data[] = get_string('not_started', 'feedback'); } - + //selections to bulk messaging if(has_capability('moodle/course:bulkmessaging', $coursecontext)) { $data[] = ''; @@ -235,9 +235,9 @@ $table->add_data($data); } $table->print_html(); - + $allurl = new moodle_url($baseurl); - + if ($showall) { $allurl->param('showall', 0); echo $OUTPUT->container(html_writer::link($allurl, get_string('showperpage', '', FEEDBACK_DEFAULT_PAGE_COUNT)), array(), 'showall'); @@ -246,7 +246,7 @@ echo $OUTPUT->container(html_writer::link($allurl, get_string('showall', '', $matchcount)), array(), 'showall'); } if(has_capability('moodle/course:bulkmessaging', $coursecontext)) { - $usehtmleditor = can_use_html_editor(); + $usehtmleditor = can_use_html_editor(); echo '
'; echo ' '; echo ' '; diff --git a/mod/forum/db/events.php b/mod/forum/db/events.php new file mode 100644 index 00000000000..1e98f789937 --- /dev/null +++ b/mod/forum/db/events.php @@ -0,0 +1,39 @@ +. + +/** + * Meta course enrolment plugin event handler definition. + * + * @package enrol_meta + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/* List of handlers */ +$handlers = array ( + 'user_enrolled' => array ( + 'handlerfile' => '/mod/forum/lib.php', + 'handlerfunction' => 'forum_user_enrolled', + 'schedule' => 'instant' + ), + + 'user_unenrolled' => array ( + 'handlerfile' => '/mod/forum/lib.php', + 'handlerfunction' => 'forum_user_unenrolled', + 'schedule' => 'instant' + ), +); diff --git a/mod/forum/db/upgrade.php b/mod/forum/db/upgrade.php index 0d4e178e2b8..1d0435a04eb 100644 --- a/mod/forum/db/upgrade.php +++ b/mod/forum/db/upgrade.php @@ -56,34 +56,6 @@ function xmldb_forum_upgrade($oldversion) { upgrade_mod_savepoint($result, 2007101511, 'forum'); } - if ($result && $oldversion < 2007101512) { - - /// Cleanup the forum subscriptions - echo $OUTPUT->notification('Removing stale forum subscriptions', 'notifysuccess'); - - $roles = get_roles_with_capability('moodle/course:participate', CAP_ALLOW); - $roles = array_keys($roles); - - list($usql, $params) = $DB->get_in_or_equal($roles); - $sql = "SELECT fs.userid, f.id AS forumid - FROM {forum} f - JOIN {course} c ON c.id = f.course - JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = ".CONTEXT_COURSE.") - JOIN {forum_subscriptions} fs ON fs.forum = f.id - LEFT JOIN {role_assignments} ra ON (ra.contextid = ctx.id AND ra.userid = fs.userid AND ra.roleid $usql) - WHERE ra.id IS NULL"; - - if ($rs = $DB->get_recordset_sql($sql, $params)) { - foreach ($rs as $remove) { - $DB->delete_records('forum_subscriptions', array('userid'=>$remove->userid, 'forum'=>$remove->forumid)); - echo '.'; - } - $rs->close(); - } - - upgrade_mod_savepoint($result, 2007101512, 'forum'); - } - if ($result && $oldversion < 2008072800) { /// Define field completiondiscussions to be added to forum $table = new xmldb_table('forum'); diff --git a/mod/forum/lib.php b/mod/forum/lib.php index 43e4f725478..0e66475cbf2 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -1428,10 +1428,10 @@ function forum_print_recent_activity($course, $viewfullnames, $timestart) { */ function forum_get_user_grades($forum, $userid=0) { global $CFG; - + require_once($CFG->dirroot.'/rating/lib.php'); $rm = new rating_manager(); - + $ratingoptions = new stdclass(); //need these to work backwards to get a context id. Is there a better way to get contextid from a module instance? @@ -1800,9 +1800,8 @@ function forum_get_readable_forums($userid, $courseid=0) { $courses = $DB->get_records('course', array('id' => $courseid)); } else { // If no course is specified, then the user can see SITE + his courses. - // And admins can see all courses, so pass the $doanything flag enabled $courses1 = $DB->get_records('course', array('id' => SITEID)); - $courses2 = get_my_courses($userid, null, null, true); + $courses2 = enrol_get_users_courses($userid, true); $courses = array_merge($courses1, $courses2); } if (!$courses) { @@ -5654,34 +5653,29 @@ function forum_update_subscriptions_button($courseid, $forumid) { } /** - * This function gets run whenever a role is assigned to a user in a context + * This function gets run whenever user is enrolled into course * - * @param integer $userid - * @param object $context - * @param itn $roleid - * @return bool + * @param object $cp + * @return void */ -function forum_role_assign($userid, $context, $roleid) { - return forum_add_user_default_subscriptions($userid, $context); +function forum_user_enrolled($cp) { + $context = get_context_instance(CONTEXT_COURSE, $cp->courseid); + forum_add_user_default_subscriptions($cp->userid, $context); } /** - * This function gets run whenever a role is assigned to a user in a context + * This function gets run whenever user is unenrolled from course * - * @param integer $userid - * @param object $context - * @return bool + * @param object $cp + * @return void */ -function forum_role_unassign($userid, $context) { - if (empty($context->contextlevel)) { - return false; +function forum_user_unenrolled($cp) { + if ($cp->lastenrol) { + $context = get_context_instance(CONTEXT_COURSE, $cp->courseid); + forum_remove_user_subscriptions($cp->userid, $context); + forum_remove_user_tracking($cp->userid, $context); } - - forum_remove_user_subscriptions($userid, $context); - forum_remove_user_tracking($userid, $context); - - return true; } @@ -5793,7 +5787,6 @@ function forum_remove_user_subscriptions($userid, $context) { switch ($context->contextlevel) { case CONTEXT_SYSTEM: // For the whole site - //if ($courses = get_my_courses($userid)) { // find all courses in which this user has a forum subscription if ($courses = $DB->get_records_sql("SELECT c.id FROM {course} c, @@ -7003,7 +6996,7 @@ function forum_reset_userdata($data) { // remove all ratings in this course's forums if (!empty($data->reset_forum_ratings)) { $ratingdeloptions = new stdclass(); - + if ($forums) { foreach ($forums as $forumid=>$unused) { if (!$cm = get_coursemodule_from_instance('forum', $forumid)) { @@ -7373,7 +7366,7 @@ function forum_get_extra_capabilities() { */ function forum_extend_navigation($navref, $course, $module, $cm) { global $CFG, $OUTPUT, $USER; - + $limit = 5; $discussions = forum_get_discussions($cm,"d.timemodified DESC", false, -1, $limit); diff --git a/mod/forum/post.php b/mod/forum/post.php index 9d51acc95a2..8a54fbdd793 100644 --- a/mod/forum/post.php +++ b/mod/forum/post.php @@ -111,7 +111,7 @@ if (!empty($forum)) { // User is starting a new discussion in a forum if (!is_enrolled($coursecontext)) { $SESSION->wantsurl = $FULLME; $SESSION->enrolcancel = $_SERVER['HTTP_REFERER']; - redirect($CFG->wwwroot.'/course/enrol.php?id='.$course->id, get_string('youneedtoenrol')); + redirect($CFG->wwwroot.'/enrol/index.php?id='.$course->id, get_string('youneedtoenrol')); } } print_error('nopostforum', 'forum'); @@ -178,7 +178,7 @@ if (!empty($forum)) { // User is starting a new discussion in a forum if (!is_enrolled($coursecontext)) { // User is a guest here! $SESSION->wantsurl = $FULLME; $SESSION->enrolcancel = $_SERVER['HTTP_REFERER']; - redirect($CFG->wwwroot.'/course/enrol.php?id='.$course->id, get_string('youneedtoenrol')); + redirect($CFG->wwwroot.'/enrol/index.php?id='.$course->id, get_string('youneedtoenrol')); } } print_error('nopostforum', 'forum'); diff --git a/notes/index.php b/notes/index.php index 7f78fb5cd24..53fed7dcd21 100644 --- a/notes/index.php +++ b/notes/index.php @@ -118,7 +118,7 @@ if ($courseid != SITEID) { echo ''; if (!empty($userid)) { - $courses = get_my_courses($userid); + $courses = enrol_get_users_courses($userid); foreach($courses as $c) { $header = '' . $c->fullname . ''; if (has_capability('moodle/notes:manage', get_context_instance(CONTEXT_COURSE, $c->id))) { diff --git a/pluginfile.php b/pluginfile.php index 9ca895015fc..243bc2ee4e7 100644 --- a/pluginfile.php +++ b/pluginfile.php @@ -220,7 +220,7 @@ if (!empty($sendflashupgrader) && (($userplayerversion[0] < $requiredplayervers if ($USER->id !== $userid) { $usercontext = get_context_instance(CONTEXT_USER, $userid); // The browsing user is not the current user - if (!has_coursemanager_role($userid) && !has_capability('moodle/user:viewdetails', $usercontext)) { + if (!has_coursecontact_role($userid) && !has_capability('moodle/user:viewdetails', $usercontext)) { send_file_not_found(); } @@ -228,7 +228,7 @@ if (!empty($sendflashupgrader) && (($userplayerversion[0] < $requiredplayervers if (has_capability('moodle/user:viewdetails', $usercontext)) { $canview = true; } else { - $courses = get_my_courses($USER->id); + $courses = enrol_get_my_courses(); } while (!$canview && count($courses) > 0) { @@ -309,28 +309,13 @@ if (!empty($sendflashupgrader) && (($userplayerversion[0] < $requiredplayervers session_get_instance()->write_close(); // unlock session during fileserving send_stored_file($file, 0, 0, true); - } else if ($filearea === 'course_intro') { + } else if ($filearea === 'course_summary') { if ($CFG->forcelogin) { require_login(); } $relativepath = '/'.implode('/', $args); - $fullpath = $context->id.'course_intro0'.$relativepath; - - if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { - send_file_not_found(); - } - - session_get_instance()->write_close(); // unlock session during fileserving - send_stored_file($file, 60*60, 0, false); // TODO: change timeout? - - } else if ($filearea === 'course_summary') { - - if ($CFG->forcelogin) { - require_login(); - } - - $fullpath = $context->id.$filearea.implode('/', $args); + $fullpath = $context->id.'course_summary0'.$relativepath; if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { send_file_not_found(); @@ -455,7 +440,7 @@ if (!empty($sendflashupgrader) && (($userplayerversion[0] < $requiredplayervers print_error('noguest'); } - if (!has_coursemanager_role($userid) and !has_capability('moodle/user:viewdetails', $usercontext)) { + if (!has_coursecontact_role($userid) and !has_capability('moodle/user:viewdetails', $usercontext)) { print_error('usernotavailable'); } if (!has_capability('moodle/user:viewdetails', $context) && diff --git a/question/type/randomsamatch/questiontype.php b/question/type/randomsamatch/questiontype.php index b3caae8b870..a774f9ba368 100644 --- a/question/type/randomsamatch/questiontype.php +++ b/question/type/randomsamatch/questiontype.php @@ -97,7 +97,7 @@ class question_randomsamatch_qtype extends question_match_qtype { $count = count($saquestions); $wanted = $question->options->choose; $errorstr = ''; - if ($count < $wanted && has_coursemanager_role()) { //TODO: this teacher test is far from optimal + if ($count < $wanted && has_coursecontact_role()) { //TODO: this teacher test is far from optimal if ($count >= 2) { $errorstr = "Error: could not get enough Short-Answer questions! Got $count Short-Answer questions, but wanted $wanted. diff --git a/repository/lib.php b/repository/lib.php index 7ad07336f0f..d12893a43c9 100644 --- a/repository/lib.php +++ b/repository/lib.php @@ -549,7 +549,7 @@ abstract class repository { $level = $context->contextlevel; if ($level == CONTEXT_COURSE) { - if (!has_capability('moodle/course:participate', $context)) { + if (!is_enrolled($context)) { //TODO: this looks a bit too simple, verify! return false; } else { return true; diff --git a/rss/file.php b/rss/file.php index e9cae889454..02640b74cc3 100644 --- a/rss/file.php +++ b/rss/file.php @@ -86,29 +86,21 @@ if (!$isblog) { if (!in_array(strtolower($modulename), $mods)) { rss_not_found(); } - //Get course_module to check it's visible - if (!$cm = get_coursemodule_from_instance($modulename,$instance)) { + try { + $cm = get_coursemodule_from_instance($modulename, $instance, 0, false, MUST_EXIST); + require_login($course, false, $cm, false, true); + } catch (Exception $e) { rss_not_found(); } - $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id); - //will $modcontext always be the same object as $context? - $isuser = has_capability('moodle/course:participate', $modcontext); + } else { - $isuser = has_capability('moodle/course:participate', $coursecontext); -} - -//Check if course allows guests -if ($course->id != SITEID) { - if ((!$course->guest || $course->password) && (!$isuser)) { + try { + require_login($course, false, NULL, false, true); + } catch (Exception $e) { rss_not_found(); } } -//Check for "security" if the course is hidden or the activity is hidden -if (!$isblog and (!$course->visible || !$cm->visible) && (!has_capability('moodle/course:viewhiddenactivities', $context))) { - rss_not_found(); -} - $pathname = null; //Work out the filename of the cached RSS file if ($isblog) { diff --git a/search/documents/label_document.php b/search/documents/label_document.php index 24301bb0e66..86a0faaf94e 100644 --- a/search/documents/label_document.php +++ b/search/documents/label_document.php @@ -165,7 +165,7 @@ function label_check_text_access($path, $itemtype, $this_id, $user, $group_id, $ $course_context = get_context_instance(CONTEXT_COURSE, $r->course); //check if englobing course is visible - if (!has_capability('moodle/course:participate', $course_context)){ + if (!is_enrolled($course_context) and !is_viewing($course_context)) { return false; } diff --git a/search/documents/resource_document.php b/search/documents/resource_document.php index dd5550e9c44..9f0f8ad3c4e 100644 --- a/search/documents/resource_document.php +++ b/search/documents/resource_document.php @@ -326,7 +326,7 @@ function resource_check_text_access($path, $itemtype, $this_id, $user, $group_id } //check if user is registered in course or course is open to guests - if (!$course->guest && !has_capability('moodle/course:participate', $course_context)) { + if (!is_enrolled($course_context) and !is_viewing($course_context)) { //TODO: guest course access is gone, this needs a different solution return false; } diff --git a/search/querylib.php b/search/querylib.php index 8a395832249..74ea57dd3e0 100644 --- a/search/querylib.php +++ b/search/querylib.php @@ -398,7 +398,7 @@ class SearchQuery { } // first check course compatibility against user : enrolled users to that course can see. - $myCourses = get_my_courses($user->id); + $myCourses = enrol_get_users_courses($user->id, true); $unenroled = !in_array($course_id, array_keys($myCourses)); // if guests are allowed, logged guest can see diff --git a/tag/coursetagslib.php b/tag/coursetagslib.php index c13300d0c53..264e5603224 100644 --- a/tag/coursetagslib.php +++ b/tag/coursetagslib.php @@ -399,7 +399,8 @@ function coursetag_get_tagged_courses($tagid) { //view, but arguably it is best that when clicking on a tag, the tagged course summary should //be seen and then if the student clicks on that they will be given the opportunity to join //note courses not visible should not have their tagid sent to this function - //if (has_capability('moodle/course:participate', get_context_instance(CONTEXT_COURSE, $c->itemid))) { + // $context = get_context_instance(CONTEXT_COURSE, $c->itemid); + //if (is_enrolled($context) oe is_viewing($context)) { $course = $DB->get_record('course', array('id'=>$c->itemid)); $courses[$c->itemid] = $course; //} diff --git a/tag/locallib.php b/tag/locallib.php index 6a6e8240332..c574c6ede5b 100644 --- a/tag/locallib.php +++ b/tag/locallib.php @@ -322,7 +322,7 @@ function tag_print_user_box($user, $return=false) { $usercontext = get_context_instance(CONTEXT_USER, $user->id); $profilelink = ''; - if ( has_capability('moodle/user:viewdetails', $usercontext) || has_coursemanager_role($user->id) ) { + if ( has_capability('moodle/user:viewdetails', $usercontext) || has_coursecontact_role($user->id) ) { $profilelink = $CFG->wwwroot .'/user/view.php?id='. $user->id; } diff --git a/user/action_redir.php b/user/action_redir.php index c64c8e1222c..21359317a05 100644 --- a/user/action_redir.php +++ b/user/action_redir.php @@ -33,8 +33,6 @@ $PAGE->set_url('/user/action_redir.php', array('formaction'=>$formaction,'id'=>$ // Add every page will be redirected by this script $actions = array( 'messageselect.php', - 'extendenrol.php', - 'groupextendenrol.php', 'addnote.php', 'groupaddnote.php', ); diff --git a/user/extendenrol.php b/user/extendenrol.php deleted file mode 100644 index 9b384e28615..00000000000 --- a/user/extendenrol.php +++ /dev/null @@ -1,188 +0,0 @@ -. - -/** - * This file is part of the User section Moodle - * - * @copyright 1999 Martin Dougiamas http://dougiamas.com - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @package user - */ - -require_once("../config.php"); - -$id = required_param('id', PARAM_INT); // course id -$users = optional_param('userid', array(), PARAM_INT); // array of user id - -$PAGE->set_url('/user/extendenrol.php', array('id'=>$id)); - -if (! $course = $DB->get_record('course', array('id'=>$id))) { - print_error('invalidcourseid'); -} - -$context = get_context_instance(CONTEXT_COURSE, $id); -require_login($course->id); - -// to extend enrolments current user needs to be able to do role assignments -require_capability('moodle/role:assign', $context); -$today = time(); -$today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0); -if ((count($users) > 0) and ($form = data_submitted()) and confirm_sesskey()) { - if (count($form->userid) != count($form->extendperiod) || count($form->userid) != count($form->extendbase)) { - print_error('invalidformdata', '', $CFG->wwwroot.'/user/index.php?id='.$id); - } - - foreach ($form->userid as $k => $v) { - // find all roles this student have in this course - if ($students = $DB->get_records_sql("SELECT ra.id, ra.roleid, ra.timestart, ra.timeend - FROM {role_assignments} ra - WHERE userid = ? - AND contextid = ?", array($v, $context->id))) { - // enrol these users again, with time extension - // not that this is not necessarily a student role - foreach ($students as $student) { - // only extend if the user can make role assignments on this role - if (user_can_assign($context, $student->roleid)) { - switch($form->extendperiod[$k]) { - case 0: // No change - break; - case -1: // unlimited - $student->timeend = 0; - break; - default: // extend - switch($form->extendbase[$k]) { - case 0: // course start date - $student->timeend = $course->startdate + $form->extendperiod[$k]; - break; - case 1: // student enrolment start date - // we check for student enrolment date because Moodle versions before 1.9 did not set this for - // unlimited enrolment courses, so it might be 0 - if($student->timestart > 0) { - $student->timeend = $student->timestart + $form->extendperiod[$k]; - } - break; - case 2: // student enrolment start date - // enrolment end equals 0 means Unlimited, so adding some time to that will still yield Unlimited - if($student->timeend > 0) { - $student->timeend = $student->timeend + $form->extendperiod[$k]; - } - break; - case 3: // current date - $student->timeend = $today + $form->extendperiod[$k]; - break; - case 4: // course enrolment start date - if($course->enrolstartdate > 0) { - $student->timeend = $course->enrolstartdate + $form->extendperiod[$k]; - } - break; - case 5: // course enrolment end date - if($course->enrolenddate > 0) { - $student->timeend = $course->enrolenddate + $form->extendperiod[$k]; - } - break; - } - } - role_assign($student->roleid, $v, 0, $context->id, $student->timestart, $student->timeend, 0); - } - } - } - } - - redirect("$CFG->wwwroot/user/index.php?id=$id", get_string('changessaved')); -} - -/// Print headers - -$PAGE->navbar->add(get_string('extendenrol')); -$PAGE->set_title("$course->shortname: ".get_string('extendenrol')); -$PAGE->set_heading( $course->fullname); - -echo $OUTPUT->header(); - -$timeformat = get_string('strftimedate'); -$unlimited = get_string('unlimited'); -$periodmenu[-1] = $unlimited; -for ($i=1; $i<=365; $i++) { - $seconds = $i * 86400; - $periodmenu[$seconds] = get_string('numdays', '', $i); -} - -// this will contain all available the based On select options, but we'll disable some on them on a per user basis -$basemenu[0] = get_string('startdate') . ' (' . userdate($course->startdate, $timeformat) . ')'; -$basemenu[1] = get_string('enrolmentstart'); -$basemenu[2] = get_string('enrolmentend'); -if($course->enrollable != 2 || ($course->enrolstartdate == 0 || $course->enrolstartdate <= $today) && ($course->enrolenddate == 0 || $course->enrolenddate > $today)) { - $basemenu[3] = get_string('today') . ' (' . userdate($today, $timeformat) . ')' ; -} -if($course->enrollable == 2) { - if($course->enrolstartdate > 0) { - $basemenu[4] = get_string('courseenrolstartdate') . ' (' . userdate($course->enrolstartdate, $timeformat) . ')'; - } - if($course->enrolenddate > 0) { - $basemenu[5] = get_string('courseenrolenddate') . ' (' . userdate($course->enrolenddate, $timeformat) . ')'; - } -} - -$title = get_string('extendenrol'); -echo $OUTPUT->heading($title . $OUTPUT->old_help_icon('extendenrol', $title)); -echo "
\n"; -echo ''; -echo ''; -$table = new html_table(); -$table->head = array (get_string('fullnameuser'), get_string('enrolmentstart'), get_string('enrolmentend'), get_string('extendperiod'), get_string('startingfrom')); -$table->align = array ('left', 'center', 'center', 'center'); -$table->width = "600"; -$nochange = get_string('nochange'); -$notavailable = get_string('notavailable'); -foreach ($_POST as $k => $v) { - if (preg_match('/^user(\d+)$/',$k,$m)) { - - if (!($user = $DB->get_record_sql("SELECT * - FROM {user} u - JOIN {role_assignments} ra ON u.id=ra.userid - WHERE u.id=? AND ra.contextid = ?", array($m[1], $context->id)))) { - continue; - } - $userbasemenu = $basemenu; - if ($user->timestart) { - $timestart = userdate($user->timestart, $timeformat); - } else { - $timestart = $notavailable; - unset($userbasemenu[1]); - } - if ($user->timeend) { - $timeend = userdate($user->timeend, $timeformat); - } else { - $timeend = $unlimited; - unset($userbasemenu[2]); - } - - $checkbox = html_writer::select($periodmenu, "extendperiod[{$m[1]}]", "0", array('0'=>$nochange)); - $checkbox2 = html_writer::select($userbasemenu, "extendbase[{$m[1]}]", "2", false); - $table->data[] = array( - fullname($user, true), - $timestart, - $timeend, - ''.$checkbox, - $checkbox2); - } -} -echo html_writer::table($table); -echo "\n
\n
\n"; - -echo $OUTPUT->footer(); - diff --git a/user/groupextendenrol.php b/user/groupextendenrol.php deleted file mode 100755 index 20073b128c0..00000000000 --- a/user/groupextendenrol.php +++ /dev/null @@ -1,185 +0,0 @@ -. - -/** - * This file is part of the User section Moodle - * - * @copyright 1999 Martin Dougiamas http://dougiamas.com - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @package user - */ - -require_once("../config.php"); - -$id = required_param('id', PARAM_INT); // course id -$users = optional_param('userid', array(), PARAM_INT); // array of user id - -$PAGE->set_url('/user/groupextendenrol.php', array('id'=>$id)); - -if (! $course = $DB->get_record('course', array('id'=>$id))) { - print_error('invalidcourseid'); -} - -$context = get_context_instance(CONTEXT_COURSE, $id); -require_login($course->id); - -// to extend enrolments current user needs to be able to do role assignments -require_capability('moodle/role:assign', $context); -$today = time(); -$today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0); - -if ((count($users) > 0) and ($form = data_submitted()) and confirm_sesskey()) { - - foreach ($form->userid as $k => $v) { - // find all roles this student have in this course - if ($students = $DB->get_records_sql("SELECT ra.id, ra.roleid, ra.timestart, ra.timeend - FROM {role_assignments} ra - WHERE userid = ? - AND contextid = ?", array($v, $context->id))) { - // enrol these users again, with time extension - // not that this is not necessarily a student role - foreach ($students as $student) { - // only extend if the user can make role assignments on this role - if (user_can_assign($context, $student->roleid)) { - switch($form->extendperiod) { - case 0: // No change (currently this option is not available in dropdown list, but it might be ...) - break; - case -1: // unlimited - $student->timeend = 0; - break; - default: // extend - switch($form->extendbase) { - case 0: // course start date - $student->timeend = $course->startdate + $form->extendperiod; - break; - case 1: // student enrolment start date - // we check for student enrolment date because Moodle versions before 1.9 did not set this for - // unlimited enrolment courses, so it might be 0 - if($student->timestart > 0) { - $student->timeend = $student->timestart + $form->extendperiod; - } - break; - case 2: // student enrolment start date - // enrolment end equals 0 means Unlimited, so adding some time to that will still yield Unlimited - if($student->timeend > 0) { - $student->timeend = $student->timeend + $form->extendperiod; - } - break; - case 3: // current date - $student->timeend = $today + $form->extendperiod; - break; - case 4: // course enrolment start date - if($course->enrolstartdate > 0) { - $student->timeend = $course->enrolstartdate + $form->extendperiod; - } - break; - case 5: // course enrolment end date - if($course->enrolenddate > 0) { - $student->timeend = $course->enrolenddate + $form->extendperiod; - } - break; - } - } - role_assign($student->roleid, $v, 0, $context->id, $student->timestart, $student->timeend, 0); - } - } - } - } - - redirect("$CFG->wwwroot/user/index.php?id=$id", get_string('changessaved')); -} - -$PAGE->navbar->add(get_string('extendenrol')); -$PAGE->set_title("$course->shortname: ".get_string('extendenrol')); -$PAGE->set_heading($course->fullname); - -/// Print headers -echo $OUTPUT->header(); - -$timeformat = get_string('strftimedate'); -$unlimited = get_string('unlimited'); -$periodmenu[-1] = $unlimited; -for ($i=1; $i<=365; $i++) { - $seconds = $i * 86400; - $periodmenu[$seconds] = get_string('numdays', '', $i); -} - -$basemenu[0] = get_string('startdate') . ' (' . userdate($course->startdate, $timeformat) . ')'; -$basemenu[1] = get_string('enrolmentstart'); -$basemenu[2] = get_string('enrolmentend'); -if($course->enrollable != 2 || ($course->enrolstartdate == 0 || $course->enrolstartdate <= $today) && ($course->enrolenddate == 0 || $course->enrolenddate > $today)) { - $basemenu[3] = get_string('today') . ' (' . userdate($today, $timeformat) . ')' ; -} -if($course->enrollable == 2) { - if($course->enrolstartdate > 0) { - $basemenu[4] = get_string('courseenrolstartdate') . ' (' . userdate($course->enrolstartdate, $timeformat) . ')'; - } - if($course->enrolenddate > 0) { - $basemenu[5] = get_string('courseenrolenddate') . ' (' . userdate($course->enrolenddate, $timeformat) . ')'; - } -} - -$title = get_string('groupextendenrol'); -echo $OUTPUT->heading($title . $OUTPUT->old_help_icon('groupextendenrol', $title)); -echo '
'; -echo ''; -echo ''; -$table = new html_table(); -$table->head = array (get_string('fullnameuser'), get_string('enrolmentstart'), get_string('enrolmentend')); -$table->align = array ('left', 'center', 'center', 'center'); -$table->width = "600"; -$nochange = get_string('nochange'); -$notavailable = get_string('notavailable'); - -foreach ($_POST as $k => $v) { - if (preg_match('/^user(\d+)$/',$k,$m)) { - - if (!($user = $DB->get_record_sql("SELECT * - FROM {user} u - JOIN {role_assignments} ra ON u.id=ra.userid - WHERE u.id=? AND ra.contextid = ?", array($m[1], $context->id)))) { - continue; - } - if ($user->timestart) { - $timestart = userdate($user->timestart, $timeformat); - } else { - $timestart = $notavailable; - } - if ($user->timeend) { - $timeend = userdate($user->timeend, $timeformat); - } else { - $timeend = $unlimited; - } - $table->data[] = array( - fullname($user, true), - $timestart, - $timeend . '' - ); - } -} -echo html_writer::table($table); -echo '
'; -echo get_string('extendperiod') . ' '; -echo html_writer::select($periodmenu, 'extendperiod'); -echo ' ' . get_string('startingfrom') . ' '; -echo html_writer::select($basemenu, 'extendbase', '2', false); -echo '
'; -echo ''; -echo '
'; - -echo $OUTPUT->footer(); - diff --git a/user/index.php b/user/index.php index be216205123..c4eb43c9798 100644 --- a/user/index.php +++ b/user/index.php @@ -11,7 +11,6 @@ define('SHOW_ALL_PAGE_SIZE', 5000); define('MODE_BRIEF', 0); define('MODE_USERDETAILS', 1); - define('MODE_ENROLDETAILS', 2); $page = optional_param('page', 0, PARAM_INT); // which page to show $perpage = optional_param('perpage', DEFAULT_PAGE_SIZE, PARAM_INT); // how many per page @@ -199,7 +198,7 @@ $controlstable->data[] = new html_table_row(); /// Print my course menus - if ($mycourses = get_my_courses($USER->id)) { + if ($mycourses = enrol_get_my_courses()) { $courselist = array(); $popupurl = new moodle_url('/user/index.php?roleid='.$roleid.'&sifirst=&silast='); foreach ($mycourses as $mycourse) { @@ -273,27 +272,8 @@ } } - // Decide wheteher we will fetch extra enrolment/groups data. - // - // MODE_ENROLDETAILS is expensive, and only suitable where the listing is small - // (at or below DEFAULT_PAGE_SIZE) and $USER can enrol/unenrol - // (will take 1 extra DB query - 2 on Oracle) - // - if (!$isfrontpage && ($perpage <= DEFAULT_PAGE_SIZE) && has_capability('moodle/role:assign',$context)) { - $allowenroldetails = true; - } else { - $allowenroldetails = false; - if ($mode === MODE_ENROLDETAILS) { - // conditions haven't been met - reset - $mode = MODE_BRIEF; - } - } - $formatmenu = array( '0' => get_string('brief'), '1' => get_string('userdetails')); - if ($allowenroldetails) { - $formatmenu['2']= get_string('enroldetails'); - } $select = new single_select($baseurl, 'mode', $formatmenu, $mode, null, 'formatmenu'); $select->set_label(get_string('userlist')); $userlistcell = new html_table_cell(); @@ -350,22 +330,6 @@ $tableheaders[] = get_string('lastaccess'); } - if ($course->enrolperiod and $roleid) { - $tablecolumns[] = 'timeend'; - $tableheaders[] = get_string('enrolmentend'); - } - - if ($mode === MODE_ENROLDETAILS) { - $tablecolumns[] = 'roles'; - $tableheaders[] = get_string('roles'); - if ($groupmode != 0) { - $tablecolumns[] = 'groups'; - $tableheaders[] = get_string('groups'); - $tablecolumns[] = 'groupings'; - $tableheaders[] = get_string('groupings', 'group'); - } - } - if ($bulkoperations) { $tablecolumns[] = 'select'; $tableheaders[] = get_string('select'); @@ -403,7 +367,7 @@ // we are looking for all users with this role assigned in this context or higher $contextlist = get_related_contexts_string($context); - list($esql, $params) = get_enrolled_sql($context, NULL, $currentgroup, 'eu'); + list($esql, $params) = get_enrolled_sql($context, NULL, $currentgroup); $joins = array("FROM {user} u"); $wheres = array(); @@ -428,16 +392,6 @@ if ($accesssince) { $wheres[] = get_course_lastaccess_sql($accesssince); } - - if ($course->enrolperiod) { - // note: this is extremely tricky now, we do not know which ra assignment - // is the one causing enrolment - better show it onl when filtering by roles - - if ($roleid) { - $select .= ", (SELECT MAX(rax.timeend) FROM {role_assignments} rax WHERE rax.userid = u.id AND rax.contextid $contextlist AND rax.roleid = :raxroleid) AS timeend"; - $params['raxroleid'] = $roleid; - } - } } // performance hacks - we preload user contexts together with accounts @@ -495,17 +449,6 @@ // list of users at the current visible page - paging makes it relatively short $userlist = $DB->get_recordset_sql("$select $from $where $sort", $params, $table->get_page_start(), $table->get_page_size()); - // - // The SELECT behind get_participants_extra() is cheaper if we pass an array - // if IDs. We could pass the SELECT we did before (with the limit bits - tricky!) - // but this is much cheaper. And in any case, it is only doable with limited numbers - // of rows anyway. On a large course it will explode badly... - // - if ($mode === MODE_ENROLDETAILS) { - $userids = $DB->get_fieldset_sql("SELECT u.id $from $where", $params, $table->get_page_start(), $table->get_page_size()); - $userlist_extra = get_participants_extra($userids, $course, $context); - } - /// If there are multiple Roles in the course, then show a drop down menu for switching if (count($rolenames) > 1) { echo '
'; @@ -709,10 +652,6 @@ $links[] = html_writer::link(new moodle_url('/course/user.php?id='. $course->id .'&user='. $user->id), get_string('activity')); } - if (has_capability('moodle/role:assign', $context) and get_user_roles($context, $user->id, false)) { // I can unassign and user has some role - $links[] = html_writer::link(new moodle_url('/course/unenrol.php?id='. $course->id .'&user='. $user->id), get_string('unenrol')); - } - if ($USER->id != $user->id && !session_is_loggedinas() && has_capability('moodle/user:loginas', $context) && !is_siteadmin($user->id)) { $links[] = html_writer::link(new moodle_url('/course/loginas.php?id='. $course->id .'&user='. $user->id .'&sesskey='. sesskey()), get_string('loginas')); } @@ -740,14 +679,6 @@ if ($userlist) { - // only show the plugin if multiple enrolment plugins - // are enabled... - if (strpos($CFG->enrol_plugins_enabled, ',')=== false) { - $showenrolplugin = true; - } else { - $showenrolplugin = false; - } - $usersprinted = array(); foreach ($userlist as $user) { if (in_array($user->id, $usersprinted)) { /// Prevent duplicates by r.hidden - MDL-13935 @@ -794,13 +725,6 @@ if (!isset($hiddenfields['lastaccess'])) { $data[] = $lastaccess; } - if ($course->enrolperiod and $roleid) { - if ($user->timeend) { - $data[] = userdate($user->timeend, $timeformat); - } else { - $data[] = get_string('unlimited'); - } - } if (isset($userlist_extra) && isset($userlist_extra[$user->id])) { $ras = $userlist_extra[$user->id]['ra']; @@ -814,11 +738,6 @@ } else { $rastring .= $rolename; } - if ($showenrolplugin) { - $rastring .= '
'; - } else { - $rastring .= ' ('. $ra['enrolplugin'] .')
'; - } } $data[] = $rastring; if ($groupmode != 0) { @@ -851,11 +770,6 @@ $displaylist['groupaddnote.php'] = get_string('groupaddnewnote', 'notes'); } - if ($context->id != $frontpagectx->id) { - $displaylist['extendenrol.php'] = get_string('extendenrol'); - $displaylist['groupextendenrol.php'] = get_string('groupextendenrol'); - } - echo $OUTPUT->old_help_icon("participantswithselectedusers", get_string("withselectedusers")); echo html_writer::tag('label', get_string("withselectedusers"), array('for'=>'formactionid')); echo html_writer::select($displaylist, 'formaction', '', array(''=>'choosedots'), array('id'=>'formactionid')); @@ -947,7 +861,6 @@ function get_participants_extra ($userids, $course, $context) { ctx.contextlevel AS ctxlevel, ctx.instanceid AS ctxinstanceid, cc.name AS ccname, ra.roleid AS roleid, - ra.enrol AS enrolplugin, g.id AS gid, g.name AS gname $gpselect FROM {role_assignments} ra @@ -981,11 +894,6 @@ function get_participants_extra ($userids, $course, $context) { // ctxname => 'name' (categories only) // ctxinstid => // roleid => $roleid - // enrol => $pluginname - // - // Might be interesting to add to RA timestart, timeend, timemodified, - // and modifierid (with an outer join to mdl_user! - // foreach ($rs as $rec) { $userid = $rec->userid; @@ -1009,8 +917,7 @@ function get_participants_extra ($userids, $course, $context) { 'ctxlevel' => $rec->ctxlevel, 'ctxinstanceid' => $rec->ctxinstanceid, 'ccname' => $rec->ccname, - 'roleid' => $rec->roleid, - 'enrolplugin' => $rec->enrolplugin); + 'roleid' => $rec->roleid); } } diff --git a/user/lib.php b/user/lib.php index fe4c08c2b57..f38be6ed3d0 100644 --- a/user/lib.php +++ b/user/lib.php @@ -98,11 +98,14 @@ function user_delete_user($user) { //move unread messages from this user to read message_move_userfrom_unread2read($user->id); + // unconditionally unenrol from all courses + enrol_user_delete($user); + // remove from all groups $DB->delete_records('groups_members', array('userid'=>$user->id)); // unenrol from all roles in all contexts - role_unassign(0, $user->id); // this might be slow but it is really needed - modules might do some extra cleanup! + role_unassign_all(array('userid'=>$user->id)); // this might be slow but it is really needed - modules might do some extra cleanup! // now do a final accesslib cleanup - removes all role assingments in user context and context itself delete_context(CONTEXT_USER, $user->id); diff --git a/user/profile.php b/user/profile.php index c6d2ea2f104..4c55951f067 100644 --- a/user/profile.php +++ b/user/profile.php @@ -325,16 +325,17 @@ profile_display_fields($user->id); if (!isset($hiddenfields['mycourses'])) { - if ($mycourses = get_my_courses($user->id, 'visible DESC,sortorder ASC', null, false, 21)) { + if ($mycourses = enrol_get_users_courses($user->id, true, NULL, 'visible DESC,sortorder ASC')) { $shown=0; $courselisting = ''; foreach ($mycourses as $mycourse) { if ($mycourse->category) { $class = ''; if ($mycourse->visible == 0) { - // get_my_courses will filter courses $USER cannot see - // if we get one with visible 0 it just means it's hidden - // ... but not from $USER + $ccontext = get_context_instance(CONTEXT_COURSE, $mycourse->id); + if (!has_capability('moodle/course:viewhiddencourses', $ccontext)) { + continue; + } $class = 'class="dimmed"'; } $courselisting .= "wwwroot}/user/view.php?id={$user->id}&course={$mycourse->id}\" $class >" . format_string($mycourse->fullname) . ", "; diff --git a/user/selector/lib.php b/user/selector/lib.php index 9bcf7a660de..e984d4fc361 100644 --- a/user/selector/lib.php +++ b/user/selector/lib.php @@ -53,7 +53,7 @@ abstract class user_selector_base { protected $preserveselected = false; /** @var boolean If only one user matches the search, should we select them automatically. */ protected $autoselectunique = false; - /** @var boolean When searching, do we only match the starts of fields (better performace) + /** @var boolean When searching, do we only match the starts of fields (better performance) * or do we match occurrences anywhere? */ protected $searchanywhere = false; /** @var mixed This is used by get selected users */ @@ -62,7 +62,7 @@ abstract class user_selector_base { /** @var boolean Used to ensure we only output the search options for one user selector on * each page. */ private static $searchoptionsoutput = false; - + /** @var array JavaScript YUI3 Module definition */ protected static $jsmodule = array( 'name' => 'user_selector', @@ -643,7 +643,7 @@ abstract class user_selector_base { } } -// User selectors for managing group memebers ================================== +// User selectors for managing group members ================================== /** * Base class to avoid duplicating code. @@ -821,8 +821,9 @@ END; AND $searchcondition"; $orderby = "ORDER BY u.lastname, u.firstname"; - $params = array_merge($searchparams, $roleparams, array('groupid'=>$this->groupid), $searchparams); + $params = array_merge($searchparams, $roleparams, $enrolparams); $params['courseid'] = $this->courseid; + $params['groupid'] = $this->groupid; if (!$this->is_validating()) { $potentialmemberscount = $DB->count_records_sql("SELECT COUNT(DISTINCT u.id) $sql", $params); @@ -835,7 +836,7 @@ END; $roles = groups_calculate_role_people($rs, $context); //don't hold onto user IDs if we're doing validation - if( empty($this->validatinguserids) ) { + if (empty($this->validatinguserids) ) { if($roles) { foreach($roles as $k=>$v) { if($v) { diff --git a/user/view.php b/user/view.php index 3019c0218e4..648a4a3da71 100644 --- a/user/view.php +++ b/user/view.php @@ -262,7 +262,7 @@ if (!isset($hiddenfields['groups'])) { // Show other courses they may be in if (!isset($hiddenfields['mycourses'])) { - if ($mycourses = get_my_courses($user->id, 'visible DESC,sortorder ASC', null, false, 21)) { + if ($mycourses = enrol_get_users_courses($user->id, true, NULL, 'visible DESC,sortorder ASC')) { $shown = 0; $courselisting = ''; foreach ($mycourses as $mycourse) { @@ -270,9 +270,10 @@ if (!isset($hiddenfields['mycourses'])) { if ($mycourse->id != $course->id){ $class = ''; if ($mycourse->visible == 0) { - // get_my_courses will filter courses $USER cannot see - // if we get one with visible 0 it just means it's hidden - // ... but not from $USER + $ccontext = get_context_instance(CONTEXT_COURSE, $mycourse->id); + if (!has_capability('moodle/course:viewhiddencourses', $ccontext)) { + continue; + } $class = 'class="dimmed"'; } $courselisting .= "wwwroot}/user/view.php?id={$user->id}&course={$mycourse->id}\" $class >" diff --git a/version.php b/version.php index 0db522b7b32..7eed065a620 100644 --- a/version.php +++ b/version.php @@ -6,7 +6,7 @@ // This is compared against the values stored in the database to determine // whether upgrades should be performed (see lib/db/*.php) - $version = 2010060800.01; // YYYYMMDD = date of the last version bump + $version = 2010062100; // YYYYMMDD = date of the last version bump // XX = daily increments $release = '2.0 Preview 3 (Build: 20100621)'; // Human-friendly version name