/** * Test assign_roles */ public function test_assign_roles() { global $USER; $this->resetAfterTest(true); $course = self::getDataGenerator()->create_course(); // Set the required capabilities by the external function. $context = context_course::instance($course->id); $roleid = $this->assignUserCapability('moodle/role:assign', $context->id); $this->assignUserCapability('moodle/course:view', $context->id, $roleid); // Add manager role to $USER. // So $USER is allowed to assign 'manager', 'editingteacher', 'teacher' and 'student'. role_assign(1, $USER->id, context_system::instance()->id); // Check the teacher role has not been assigned to $USER. $users = get_role_users(3, $context); $this->assertEquals(count($users), 0); // Call the external function. Assign teacher role to $USER with contextid. core_role_external::assign_roles(array(array('roleid' => 3, 'userid' => $USER->id, 'contextid' => $context->id))); // Check the role has been assigned. $users = get_role_users(3, $context); $this->assertEquals(count($users), 1); // Unassign role. role_unassign(3, $USER->id, $context->id); $users = get_role_users(3, $context); $this->assertEquals(count($users), 0); // Call the external function. Assign teacher role to $USER. core_role_external::assign_roles(array(array('roleid' => 3, 'userid' => $USER->id, 'contextlevel' => "course", 'instanceid' => $course->id))); $users = get_role_users(3, $context); $this->assertEquals(count($users), 1); // Call without required capability. $this->unassignUserCapability('moodle/role:assign', $context->id, $roleid); $this->expectException('moodle_exception'); $categories = core_role_external::assign_roles(array('roleid' => 3, 'userid' => $USER->id, 'contextid' => $context->id)); }
function _unenrollUserFromCourse($user, $course) { $retVal = true; echo "<br> {$username} is now going to be unenrolled from {$course->fullname}."; if (unenrollQSUser($user, $course)) { echo "<br> unenrollQSUser for {$user->username} and {$course->fullname} was successful."; if (enrollUserInCourse($user->username, $user->username, $course->fullname, false)) { echo "<br> enrollUserInCourse for {$user->username} and {$course->fullname} and false was successful."; if (!($context = get_context_instance(CONTEXT_COURSE, $course->id))) { echo "<br> Course context for {$course->fullname} is invalid"; admin_moodlefailed_email($user, 'unenrollUser', $course); $retVal = false; } echo "<br> Course context id is {$context->id}"; if (!role_unassign(0, $user->id, 0, $context->id)) { echo "An error occurred in role_unassign while trying to unenroll {$username} from vLab via auto-delete."; admin_moodlefailed_email($user, 'unenrollUser', $course); $retVal = false; } echo "<br> role_unassign for user id of {$user->id} and context id of {$context->id} was successful."; send_unenrollment_notification($course, $user); add_to_log($course->id, 'course', 'unenrol', "auto-delete", $course->id); } else { enrollQSUser($user, $course); echo "An error occurred in enrollUserInCourse while trying to unenrll {$username} from vLab via auto-delete."; admin_moodlefailed_email($user, 'unenrollUser', $course); $retVal = false; } } else { echo "An error occurred in unenrollQSUser while trying to unenroll {$username} from vLab via auto-delete."; admin_moodlefailed_email($user, 'unenrollUser', $course); $retVal = false; } return $retVal; }
function perform_remove($userid) { // Try to remove the necessary role $context = get_context_instance(CONTEXT_SYSTEM); $roleid = $this->check_role(); // Regardless if the user has the role or not, remove the assignment if ($assign = get_record('block_student_' . $this->type, 'path', $this->path, 'usersid', $userid)) { $this->remove_assignment($assign); } $count = count_records('block_student_' . $this->type, 'usersid', $userid) + count_records('block_student_person', 'usersid', $userid); // If they don't have any mentor assignments, then remove them from that role if ($count == 0) { role_unassign($roleid, $userid, 0, $context->id); } }
function delete_user($user) { $updateuser = new object(); $updateuser->id = $user->id; $updateuser->deleted = 1; $updateuser->username = addslashes("{$user->email}." . time()); $updateuser->email = ''; $updateuser->idnumber = ''; $updateuser->timemodified = time(); if (update_record('user', $updateuser)) { role_unassign(0, $user->id); return true; } else { return false; } }
} 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'); $navlinks = array(); $navlinks[] = array('name' => $strunenrol, 'link' => null, 'type' => 'misc'); $navigation = build_navigation($navlinks); print_header("{$course->shortname}: {$strunenrol}", $course->fullname, $navigation); if ($userid) { if (!($user = $DB->get_record('user', array('id' => $userid)))) {
/** * Forces synchronisation of all enrolments with external database. * * @param bool $verbose * @param null|int $onecourse limit sync to one course only (used primarily in restore) * @return int 0 means success, 1 db connect failure, 2 db read failure */ public function sync_enrolments($verbose = false, $onecourse = null) { 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')) { if ($verbose) { mtrace('User enrolment synchronisation skipped.'); } return 0; } if ($verbose) { mtrace('Starting user enrolment synchronisation...'); } if (!($extdb = $this->db_init())) { mtrace('Error while communicating with external enrolment database'); return 1; } // We may need a lot of memory here. @set_time_limit(0); raise_memory_limit(MEMORY_HUGE); $table = $this->get_config('remoteenroltable'); $coursefield = trim($this->get_config('remotecoursefield')); $userfield = trim($this->get_config('remoteuserfield')); $rolefield = trim($this->get_config('remoterolefield')); // Lowercased versions - necessary because we normalise the resultset with array_change_key_case(). $coursefield_l = strtolower($coursefield); $userfield_l = strtolower($userfield); $rolefield_l = strtolower($rolefield); $localrolefield = $this->get_config('localrolefield'); $localuserfield = $this->get_config('localuserfield'); $localcoursefield = $this->get_config('localcoursefield'); $unenrolaction = $this->get_config('unenrolaction'); $defaultrole = $this->get_config('defaultrole'); // Create roles mapping. $allroles = get_all_roles(); if (!isset($allroles[$defaultrole])) { $defaultrole = 0; } $roles = array(); foreach ($allroles as $role) { $roles[$role->{$localrolefield}] = $role->id; } if ($onecourse) { $sql = "SELECT c.id, c.visible, c.{$localcoursefield} AS mapping, c.shortname, e.id AS enrolid\n FROM {course} c\n LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')\n WHERE c.id = :id"; if (!($course = $DB->get_record_sql($sql, array('id' => $onecourse)))) { // Course does not exist, nothing to sync. return 0; } if (empty($course->mapping)) { // We can not map to this course, sorry. return 0; } if (empty($course->enrolid)) { $course->enrolid = $this->add_instance($course); } $existing = array($course->mapping => $course); // Feel free to unenrol everybody, no safety tricks here. $preventfullunenrol = false; // Course being restored are always hidden, we have to ignore the setting here. $ignorehidden = false; } else { // Get a list of courses to be synced that are in external table. $externalcourses = array(); $sql = $this->db_get_sql($table, array(), array($coursefield), true); if ($rs = $extdb->Execute($sql)) { if (!$rs->EOF) { while ($mapping = $rs->FetchRow()) { $mapping = reset($mapping); $mapping = $this->db_decode($mapping); if (empty($mapping)) { // invalid mapping continue; } $externalcourses[$mapping] = true; } } $rs->Close(); } else { mtrace('Error reading data from the external enrolment table'); $extdb->Close(); return 2; } $preventfullunenrol = empty($externalcourses); if ($preventfullunenrol and $unenrolaction == ENROL_EXT_REMOVED_UNENROL) { mtrace(' Preventing unenrolment of all current users, because it might result in major data loss, there has to be at least one record in external enrol table, sorry.'); } // First find all existing courses with enrol instance. $existing = array(); $sql = "SELECT c.id, c.visible, c.{$localcoursefield} AS mapping, e.id AS enrolid, c.shortname\n FROM {course} c\n JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')"; $rs = $DB->get_recordset_sql($sql); // Watch out for idnumber duplicates. foreach ($rs as $course) { if (empty($course->mapping)) { continue; } $existing[$course->mapping] = $course; unset($externalcourses[$course->mapping]); } $rs->close(); // Add necessary enrol instances that are not present yet. $params = array(); $localnotempty = ""; if ($localcoursefield !== 'id') { $localnotempty = "AND c.{$localcoursefield} <> :lcfe"; $params['lcfe'] = $DB->sql_empty(); } $sql = "SELECT c.id, c.visible, c.{$localcoursefield} AS mapping, c.shortname\n FROM {course} c\n LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')\n WHERE e.id IS NULL {$localnotempty}"; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $course) { if (empty($course->mapping)) { continue; } if (!isset($externalcourses[$course->mapping])) { // Course not synced or duplicate. continue; } $course->enrolid = $this->add_instance($course); $existing[$course->mapping] = $course; unset($externalcourses[$course->mapping]); } $rs->close(); // Print list of missing courses. if ($verbose and $externalcourses) { $list = implode(', ', array_keys($externalcourses)); mtrace(" error: following courses do not exist - {$list}"); unset($list); } // Free memory. unset($externalcourses); $ignorehidden = $this->get_config('ignorehiddencourses'); } // Sync user enrolments. $sqlfields = array($userfield); if ($rolefield) { $sqlfields[] = $rolefield; } foreach ($existing as $course) { if ($ignorehidden and !$course->visible) { continue; } if (!($instance = $DB->get_record('enrol', array('id' => $course->enrolid)))) { continue; // Weird! } $context = context_course::instance($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\n FROM {user} u\n JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid)\n JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.itemid = ue.enrolid AND ra.component = 'enrol_database')\n 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), $sqlfields); if ($rs = $extdb->Execute($sql)) { if (!$rs->EOF) { $usersearch = array('deleted' => 0); if ($localuserfield === 'username') { $usersearch['mnethostid'] = $CFG->mnet_localhost_id; } while ($fields = $rs->FetchRow()) { $fields = array_change_key_case($fields, CASE_LOWER); if (empty($fields[$userfield_l])) { if ($verbose) { mtrace(" error: skipping user without mandatory {$localuserfield} in course '{$course->mapping}'"); } continue; } $mapping = $fields[$userfield_l]; if (!isset($user_mapping[$mapping])) { $usersearch[$localuserfield] = $mapping; if (!($user = $DB->get_record('user', $usersearch, 'id', IGNORE_MULTIPLE))) { if ($verbose) { mtrace(" error: skipping unknown user {$localuserfield} '{$mapping}' in course '{$course->mapping}'"); } continue; } $user_mapping[$mapping] = $user->id; $userid = $user->id; } else { $userid = $user_mapping[$mapping]; } if (empty($fields[$rolefield_l]) or !isset($roles[$fields[$rolefield_l]])) { if (!$defaultrole) { if ($verbose) { mtrace(" error: skipping user '{$userid}' in course '{$course->mapping}' - missing course and default role"); } continue; } $roleid = $defaultrole; } else { $roleid = $roles[$fields[$rolefield_l]]; } $requested_roles[$userid][$roleid] = $roleid; } } $rs->Close(); } else { mtrace(" error: skipping course '{$course->mapping}' - could not match with external database"); continue; } unset($user_mapping); // Enrol all users and sync roles. foreach ($requested_roles as $userid => $userroles) { foreach ($userroles as $roleid) { if (empty($current_roles[$userid])) { $this->enrol_user($instance, $userid, $roleid, 0, 0, ENROL_USER_ACTIVE); $current_roles[$userid][$roleid] = $roleid; $current_status[$userid] = ENROL_USER_ACTIVE; if ($verbose) { mtrace(" enrolling: {$userid} ==> {$course->shortname} as " . $allroles[$roleid]->shortname); } } } // Assign extra roles. foreach ($userroles as $roleid) { if (empty($current_roles[$userid][$roleid])) { role_assign($roleid, $userid, $context->id, 'enrol_database', $instance->id); $current_roles[$userid][$roleid] = $roleid; if ($verbose) { mtrace(" assigning roles: {$userid} ==> {$course->shortname} as " . $allroles[$roleid]->shortname); } } } // Unassign removed roles. foreach ($current_roles[$userid] as $cr) { if (empty($userroles[$cr])) { role_unassign($cr, $userid, $context->id, 'enrol_database', $instance->id); unset($current_roles[$userid][$cr]); if ($verbose) { mtrace(" unsassigning roles: {$userid} ==> {$course->shortname}"); } } } // Reenable enrolment when previously disable enrolment refreshed. if ($current_status[$userid] == ENROL_USER_SUSPENDED) { $this->update_user_enrol($instance, $userid, ENROL_USER_ACTIVE); if ($verbose) { mtrace(" unsuspending: {$userid} ==> {$course->shortname}"); } } } // Deal with enrolments removed from external table. if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) { if (!$preventfullunenrol) { // Unenrol. foreach ($current_status as $userid => $status) { if (isset($requested_roles[$userid])) { continue; } $this->unenrol_user($instance, $userid); if ($verbose) { mtrace(" unenrolling: {$userid} ==> {$course->shortname}"); } } } } else { if ($unenrolaction == ENROL_EXT_REMOVED_KEEP) { // Keep - only adding enrolments. } else { if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND or $unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) { // Suspend enrolments. foreach ($current_status as $userid => $status) { if (isset($requested_roles[$userid])) { continue; } if ($status != ENROL_USER_SUSPENDED) { $this->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED); if ($verbose) { mtrace(" suspending: {$userid} ==> {$course->shortname}"); } } if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) { role_unassign_all(array('contextid' => $context->id, 'userid' => $userid, 'component' => 'enrol_database', 'itemid' => $instance->id)); if ($verbose) { mtrace(" unsassigning all roles: {$userid} ==> {$course->shortname}"); } } } } } } } // Close db connection. $extdb->Close(); if ($verbose) { mtrace('...user enrolment synchronisation finished.'); } return 0; }
/** * Synchronise user enrolments in given instance as fast as possible. * * All roles are removed if the meta plugin disabled. * * @static * @param stdClass $instance * @param int $userid * @return void */ protected static function sync_with_parent_course(stdClass $instance, $userid) { global $DB, $CFG; $plugin = enrol_get_plugin('meta'); if ($instance->customint1 == $instance->courseid) { // can not sync with self!!! return; } $context = context_course::instance($instance->courseid); if (!($parentcontext = context_course::instance($instance->customint1, IGNORE_MISSING))) { // linking to missing course is not possible role_unassign_all(array('userid' => $userid, 'contextid' => $context->id, 'component' => 'enrol_meta')); return; } // list of enrolments in parent course (we ignore meta enrols in parents completely) list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e'); $params['userid'] = $userid; $params['parentcourse'] = $instance->customint1; $sql = "SELECT ue.*\n FROM {user_enrolments} ue\n JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol <> 'meta' AND e.courseid = :parentcourse AND e.enrol {$enabled})\n WHERE ue.userid = :userid"; $parentues = $DB->get_records_sql($sql, $params); // current enrolments for this instance $ue = $DB->get_record('user_enrolments', array('enrolid' => $instance->id, 'userid' => $userid)); // first deal with users that are not enrolled in parent if (empty($parentues)) { self::user_not_supposed_to_be_here($instance, $ue, $context, $plugin); return; } if (!enrol_is_enabled('meta')) { if ($ue) { role_unassign_all(array('userid' => $userid, 'contextid' => $context->id, 'component' => 'enrol_meta')); } return; } $skiproles = $plugin->get_config('nosyncroleids', ''); $skiproles = empty($skiproles) ? array() : explode(',', $skiproles); $syncall = $plugin->get_config('syncall', 1); // roles in parent course (meta enrols must be ignored!) $parentroles = array(); list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1); $params['contextid'] = $parentcontext->id; $params['userid'] = $userid; $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid {$ignoreroles}"; foreach ($DB->get_records_select('role_assignments', $select, $params) as $ra) { $parentroles[$ra->roleid] = $ra->roleid; } // roles from this instance $roles = array(); $ras = $DB->get_records('role_assignments', array('contextid' => $context->id, 'userid' => $userid, 'component' => 'enrol_meta', 'itemid' => $instance->id)); foreach ($ras as $ra) { $roles[$ra->roleid] = $ra->roleid; } unset($ras); // do we want users without roles? if (!$syncall and empty($parentroles)) { self::user_not_supposed_to_be_here($instance, $ue, $context, $plugin); return; } // is parent enrol active? (we ignore enrol starts and ends, sorry it would be too complex) $parentstatus = ENROL_USER_SUSPENDED; foreach ($parentues as $pue) { if ($pue->status == ENROL_USER_ACTIVE) { $parentstatus = ENROL_USER_ACTIVE; break; } } // enrol user if not enrolled yet or fix status if ($ue) { if ($parentstatus != $ue->status) { $plugin->update_user_enrol($instance, $userid, $parentstatus); $ue->status = $parentstatus; } } else { $plugin->enrol_user($instance, $userid, NULL, 0, 0, $parentstatus); $ue = new stdClass(); $ue->userid = $userid; $ue->enrolid = $instance->id; $ue->status = $parentstatus; } // only active users in enabled instances are supposed to have roles (we can reassign the roles any time later) if ($ue->status != ENROL_USER_ACTIVE or $instance->status != ENROL_INSTANCE_ENABLED) { if ($roles) { role_unassign_all(array('userid' => $userid, 'contextid' => $context->id, 'component' => 'enrol_meta', 'itemid' => $instance->id)); } return; } // add new roles foreach ($parentroles as $rid) { if (!isset($roles[$rid])) { role_assign($rid, $userid, $context->id, 'enrol_meta', $instance->id); } } // remove roles foreach ($roles as $rid) { if (!isset($parentroles[$rid])) { role_unassign($rid, $userid, $context->id, 'enrol_meta', $instance->id); } } }
echo "<br> \$destination is set to {$destination}"; if (!enrollQSUser($user, $course)) { //Added: 12.30.2010 echo "<br> enrollQSUser was NOT successful"; admin_webservicefailed_email($user, 'enrollUser', $course); if (!role_unassign(0, $user->id, 0, $context->id)) { // Should email the Admin if this happens error("An error occurred while trying to unenrol that person."); exit; } //admin_moodlefailed_email($user,'unenrollUser'); } else { echo "<br> enrollQSUser was successful"; if (!enrollUserInCourse($user->username, $user->username, $course->fullname, true)) { echo "<br> enrollUserInCourse was NOT successful"; if (!role_unassign(0, $user->id, 0, $context->id)) { error("An error occurred while trying to unenrol that person."); exit; } echo "<br> role_unassign was successful"; // Should email the Admin if this happens unenrollQSUser($user, $course); admin_webservicefailed_email($user, 'enrollUser', $course); } echo "<br> enrollUserInCourse was successful"; } $payload = file_get_contents($destination); send_enrollment_notification($course, $user); } else { echo "<br> User {$user->username} was already enrolled in course {$course->fullname}"; }
function sync_enrolments($type, $enrol = false) { global $CFG; // Get the role. If it doesn't exist, that is bad. $role = get_record('role', 'shortname', $type); if (!$role) { notify("No such role: {$type}"); return false; } // Connect to the external database $ldap_connection = $this->enrol_ldap_connect(); if (!$ldap_connection) { @ldap_close($ldap_connection); notify("LDAP-module cannot connect to server: {$CFG->ldap_host_url}"); return false; } // we are connected OK, continue... $this->enrol_ldap_bind($ldap_connection); //get all contexts and look for first matching user $ldap_contexts = explode(";", $CFG->{'enrol_ldap_contexts_role' . $role->id}); // get all the fields we will want for the potential course creation // as they are light. don't get membership -- potentially a lot of data. $ldap_fields_wanted = array('dn', $CFG->enrol_ldap_course_idnumber); if (!empty($CFG->enrol_ldap_course_fullname)) { array_push($ldap_fields_wanted, $CFG->enrol_ldap_course_fullname); } if (!empty($CFG->enrol_ldap_course_shortname)) { array_push($ldap_fields_wanted, $CFG->enrol_ldap_course_shortname); } if (!empty($CFG->enrol_ldap_course_summary)) { array_push($ldap_fields_wanted, $CFG->enrol_ldap_course_summary); } if ($enrol) { array_push($ldap_fields_wanted, $CFG->{'enrol_ldap_memberattribute_role' . $role->id}); } // define the search pattern if (!empty($CFG->enrol_ldap_objectclass)) { $ldap_search_pattern = '(objectclass=' . $CFG->enrol_ldap_objectclass . ')'; } else { $ldap_search_pattern = "(objectclass=*)"; } // first, pack the sortorder... fix_course_sortorder(); foreach ($ldap_contexts as $context) { $context = trim($context); if ($CFG->enrol_ldap_search_sub) { //use ldap_search to find first user from subtree $ldap_result = @ldap_search($ldap_connection, $context, $ldap_search_pattern, $ldap_fields_wanted); } else { //search only in this context $ldap_result = @ldap_list($ldap_connection, $context, $ldap_search_pattern, $ldap_fields_wanted, 0, 0); } // check and push results $records = $ldap_result ? ldap_get_entries($ldap_connection, $ldap_result) : array('count' => 0); // ldap libraries return an odd array, really. fix it: $flat_records = array(); for ($c = 0; $c < $records['count']; $c++) { array_push($flat_records, $records["{$c}"]); } // free mem -- is there a leak? $records = 0; $ldap_result = 0; if (count($flat_records)) { foreach ($flat_records as $course) { $idnumber = $course[$CFG->enrol_ldap_course_idnumber][0]; print "== Synching {$idnumber}\n"; // does the course exist in moodle already? $course_obj = false; $course_obj = get_record('course', $this->enrol_localcoursefield, $idnumber); if (!is_object($course_obj)) { // ok, now then let's create it! print "Creating Course {$idnumber}..."; $newcourseid = $this->create_course($course, true); // we are skipping fix_course_sortorder() $course_obj = get_record('course', 'id', $newcourseid); if (is_object($course_obj)) { print "OK!\n"; } else { print "failed\n"; } } // enrol&unenrol if required if ($enrol && is_object($course_obj)) { // Get a context object. $context = get_context_instance(CONTEXT_COURSE, $course_obj->id); // pull the ldap membership into a nice array // this is an odd array -- mix of hash and array -- $ldapmembers = array(); if (array_key_exists('enrol_ldap_memberattribute_role' . $role->id, $CFG) && !empty($CFG->{'enrol_ldap_memberattribute_role' . $role->id}) && !empty($course[strtolower($CFG->{'enrol_ldap_memberattribute_role' . $role->id})])) { // may have no membership! $ldapmembers = $course[strtolower($CFG->{'enrol_ldap_memberattribute_role' . $role->id})]; unset($ldapmembers['count']); // remove oddity ;) $ldapmembers = addslashes_recursive($ldapmembers); } // prune old ldap enrolments // hopefully they'll fit in the max buffer size for the RDBMS $sql = ' SELECT enr.userid AS user, 1 FROM ' . $CFG->prefix . 'role_assignments enr JOIN ' . $CFG->prefix . 'user usr ON usr.id=enr.userid WHERE enr.roleid = ' . $role->id . ' AND enr.contextid = ' . $context->id . ' AND enr.enrol = \'ldap\' '; if (!empty($ldapmembers)) { $sql .= 'AND usr.idnumber NOT IN (\'' . join('\',\'', $ldapmembers) . '\')'; } else { print "Empty enrolment for {$course_obj->shortname} \n"; } $todelete = get_records_sql($sql); if (!empty($todelete)) { 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"; } } } // insert current enrolments // bad we can't do INSERT IGNORE with postgres... foreach ($ldapmembers as $ldapmember) { $sql = 'SELECT id,1 FROM ' . $CFG->prefix . 'user ' . " WHERE idnumber='{$ldapmember}'"; $member = get_record_sql($sql); // print "sql: $sql \nidnumber = ".stripslashes($ldapmember)." \n".var_dump($member); if (empty($member) || empty($member->id)) { print "Could not find user " . stripslashes($ldapmember) . ", skipping\n"; continue; } $member = $member->id; if (!get_record('role_assignments', 'roleid', $role->id, 'contextid', $context->id, 'userid', $member, 'enrol', 'ldap')) { if (role_assign($role->id, $member, 0, $context->id, 0, 0, 0, 'ldap')) { print "Assigned role {$type} to {$member} (" . stripslashes($ldapmember) . ") for course {$course_obj->id} ({$course_obj->shortname})\n"; } else { print "Failed to assign role {$type} to {$member} (" . stripslashes($ldapmember) . ") for course {$course_obj->id} ({$course_obj->shortname})\n"; } } } } } } } // we are done now, a bit of housekeeping fix_course_sortorder(); @ldap_close($ldap_connection); return true; }
$sysrolename = $user->{$column}; if ($sysrolename[0] == '-') { $removing = true; $sysrolename = substr($sysrolename, 1); } else { $removing = false; } if (array_key_exists($sysrolename, $sysrolecache)) { $sysroleid = $sysrolecache[$sysrolename]->id; } else { $upt->track('enrolments', get_string('unknownrole', 'error', s($sysrolename)), 'error'); continue; } if ($removing) { if (user_has_role_assignment($user->id, $sysroleid, SYSCONTEXTID)) { role_unassign($sysroleid, $user->id, SYSCONTEXTID); $upt->track('enrolments', get_string('unassignedsysrole', 'tool_uploaduser', $sysrolecache[$sysroleid]->name)); } } else { if (!user_has_role_assignment($user->id, $sysroleid, SYSCONTEXTID)) { role_assign($sysroleid, $user->id, SYSCONTEXTID); $upt->track('enrolments', get_string('assignedsysrole', 'tool_uploaduser', $sysrolecache[$sysroleid]->name)); } } } continue; } if (!preg_match('/^course\\d+$/', $column)) { continue; } $i = substr($column, 6);
echo "<p>Error: could not access paypal.com</p>"; email_paypal_error_to_admin("Could not access paypal.com to verify payment", $data); die; } /// Connection is OK, so now we post the data to validate it fputs($fp, $header . $req); /// Now read the response and check if everything is OK. while (!feof($fp)) { $result = fgets($fp, 1024); if (strcmp($result, "VERIFIED") == 0) { // VALID PAYMENT! // check the payment_status and payment_reason // If status is not completed or pending then unenrol the student if already enrolled // and notify admin if ($data->payment_status != "Completed" and $data->payment_status != "Pending") { role_unassign(0, $data->userid, 0, $context->id); // force accessinfo refresh for users visiting this context... mark_context_dirty($context->path); email_paypal_error_to_admin("Status not completed or pending. User unenrolled from course", $data); die; } // If status is pending and reason is other than echeck then we are on hold until further notice // Email user to let them know. Email admin. if ($data->payment_status == "Pending" and $data->pending_reason != "echeck") { email_to_user($user, get_admin(), "Moodle: PayPal payment", "Your PayPal payment is pending."); email_paypal_error_to_admin("Payment pending", $data); die; } // If our status is not completed or not pending on an echeck clearance then ignore and die // This check is redundant at present but may be useful if paypal extend the return codes in the future if (!($data->payment_status == "Completed" or $data->payment_status == "Pending" and $data->pending_reason == "echeck")) {
function remove_user_role($username, $course_id, $role_id) { global $DB; $username = utf8_decode($username); $username = strtolower($username); $params = array('username' => $username); $user = $DB->get_record('user', $params); if (!$user) { return; } $params = array('id' => $course_id); $course = $DB->get_record('course', $params); $context = context_course::instance($course->id); if (!$context) { return; } if (!role_unassign($role_id, $user->id, $context->id)) { return; } }
/** * 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; global $db; error_reporting(E_ALL); // Connect to the external database $enroldb = $this->enrol_connect(); if (!$enroldb) { notify("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 = get_record('role', '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; } begin_sql(); $extcourses = array(); while ($extcourse_obj = rs_fetch_next_record($rs)) { // there are more course records $extcourse_obj = (object) array_change_key_case((array) $extcourse_obj, CASE_LOWER); $extcourse = $extcourse_obj->{strtolower($CFG->enrol_remotecoursefield)}; array_push($extcourses, $extcourse); // does the course exist in moodle already? $course = false; $course = get_record('course', $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 = get_record('course', '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 ($crs_obj = rs_fetch_next_record($crs)) { $crs_obj = (object) array_change_key_case((array) $crs_obj, CASE_LOWER); array_push($extenrolments, $crs_obj->{strtolower($CFG->enrol_remoteuserfield)}); } rs_close($crs); // 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) { $to_prune = get_records_sql("\n SELECT ra.*\n FROM {$CFG->prefix}role_assignments ra\n JOIN {$CFG->prefix}user u ON ra.userid = u.id\n WHERE ra.enrol = 'database'\n AND ra.contextid = {$context->id}\n AND ra.roleid = " . $role->id . ($extenrolments ? " AND u.{$CFG->enrol_localuserfield} NOT IN (" . join(", ", array_map(array(&$db, 'quote'), $extenrolments)) . ")" : '')); 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 = "\n SELECT u.id AS userid, ra.id AS enrolmentid\n FROM {$CFG->prefix}user u\n LEFT OUTER JOIN {$CFG->prefix}role_assignments ra ON u.id = ra.userid\n AND ra.roleid = {$role->id}\n AND ra.contextid = {$context->id}\n WHERE u.{$CFG->enrol_localuserfield} = " . $db->quote($member) . " AND (u.deleted IS NULL OR u.deleted=0) "; $ers = $db->Execute($sql); if (!$ers) { trigger_error($db->ErrorMsg() . ' STATEMENT: ' . $sql); return false; } if ($ers->EOF) { // 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; } $user_obj = rs_fetch_record($ers); $userid = $user_obj->userid; $enrolmentid = $user_obj->enrolmentid; rs_close($ers); // release the handle 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($rs); //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) { $sql = "\n SELECT ra.roleid, ra.userid, ra.contextid\n FROM {$CFG->prefix}role_assignments ra\n JOIN {$CFG->prefix}context cn ON cn.id = ra.contextid\n JOIN {$CFG->prefix}course c ON c.id = cn.instanceid\n WHERE ra.enrol = 'database'\n AND cn.contextlevel = " . CONTEXT_COURSE . " " . ($have_role ? ' AND ra.roleid = ' . $role->id : '') . ($extcourses ? " AND c.{$CFG->enrol_localcoursefield} NOT IN (" . join(",", array_map(array(&$db, 'quote'), $extcourses)) . ")" : ''); $ers = $db->Execute($sql); if (!$ers) { trigger_error($db->ErrorMsg() . ' STATEMENT: ' . $sql); return false; } if (!$ers->EOF) { while ($user_obj = rs_fetch_next_record($ers)) { $user_obj = (object) array_change_key_case((array) $user_obj, CASE_LOWER); $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}"); } } rs_close($ers); // release the handle } } commit_sql(); // we are done now, a bit of housekeeping fix_course_sortorder(); $this->enrol_disconnect($enroldb); return true; }
public function process($departmentid, $roletype) { global $DB, $USER; $companymanagerrole = $DB->get_record('role', array('shortname' => 'companymanager')); $departmentmanagerrole = $DB->get_record('role', array('shortname' => 'companydepartmentmanager')); $companycoursenoneditorrole = $DB->get_record('role', array('shortname' => 'companycoursenoneditor')); $companycourseeditorrole = $DB->get_record('role', array('shortname' => 'companycourseeditor')); // Process incoming assignments. if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) { $userstoassign = $this->potentialusers->get_selected_users(); if (!empty($userstoassign)) { foreach ($userstoassign as $adduser) { $allow = true; // GWL : Check the userid is valid. if (!company::check_valid_user($this->selectedcompany, $adduser->id, $this->departmentid)) { print_error('invaliduserdepartment', 'block_iomad_company_management'); } if ($allow) { if ($roletype != 0) { // Adding a manager type. // Add user to the company manager table. if ($userrecord = $DB->get_record('company_users', array('companyid' => $this->selectedcompany, 'userid' => $adduser->id))) { if ($roletype == 1 && $userrecord->managertype == 0) { // Give them the company manager role. role_assign($companymanagerrole->id, $adduser->id, $this->context->id); // Deal with company courses. if ($companycourses = $DB->get_records('company_course', array('companyid' => $this->selectedcompany))) { foreach ($companycourses as $companycourse) { if ($DB->record_exists('course', array('id' => $companycourse->courseid))) { if ($DB->record_exists('company_created_courses', array('companyid' => $companycourse->companyid, 'courseid' => $companycourse->courseid))) { company_user::enrol($adduser, array($companycourse->courseid), $companycourse->companyid, $companycourseeditorrole->id); } else { company_user::enrol($adduser, array($companycourse->courseid), $companycourse->companyid, $companycoursenoneditorrole->id); } } } } } else { if ($roletype == 2 && $userrecord->managertype == 0) { // Give them the department manager role. role_assign($departmentmanagerrole->id, $adduser->id, $this->context->id); // Deal with company courses. if ($companycourses = $DB->get_records('company_course', array('companyid' => $this->selectedcompany))) { foreach ($companycourses as $companycourse) { if ($DB->record_exists('course', array('id' => $companycourse->courseid))) { company_user::enrol($adduser, array($companycourse->courseid), $companycourse->companyid, $companycoursenoneditorrole->id); } } } } else { if ($roletype == 1 && ($userrecord->managertype = 2)) { // Give them the department manager role. role_unassign($departmentmanagerrole->id, $adduser->id, $this->context->id); role_assign($companymanagerrole->id, $adduser->id, $this->context->id); // Deal with course permissions. if ($companycourses = $DB->get_records('company_course', array('companyid' => $this->selectedcompany))) { foreach ($companycourses as $companycourse) { if ($DB->record_exists('course', array('id' => $companycourse->courseid))) { // If its a company created course then assign the editor role to the user. if ($DB->record_exists('company_created_courses', array('companyid' => $this->selectedcompany, 'courseid' => $companycourse->courseid))) { company_user::unenrol($adduser, array($companycourse->courseid), $companycourse->companyid); company_user::enrol($adduser, array($companycourse->courseid), $companycourse->companyid, $companycourseeditorrole->id); } else { company_user::enrol($adduser, array($companycourse->courseid), $companycourse->companyid, $companycoursenoneditorrole->id); } } } } } else { if ($roletype == 2 && ($userrecord->managertype = 1)) { // Give them the department manager role. role_unassign($companymanagerrole->id, $adduser->id, $this->context->id); role_assign($departmentmanagerrole->id, $adduser->id, $this->context->id); // Deal with company course roles. if ($companycourses = $DB->get_records('company_course', array('companyid' => $this->selectedcompany))) { foreach ($companycourses as $companycourse) { if ($DB->record_exists('course', array('id' => $companycourse->courseid))) { company_user::unenrol($adduser, array($companycourse->courseid), $companycourse->companyid); company_user::enrol($adduser, array($companycourse->courseid), $companycourse->companyid, $companycoursenoneditorrole->id); } } } } } } } $userrecord->managertype = $roletype; $DB->update_record('company_users', $userrecord); } else { if ($roletype == 1 && $DB->get_records_sql('SELECT id FROM {company_users} WHERE userid = :userid AND managertype = :roletype AND companyid != :companyid', array('userid' => $adduser->id, 'roletype' => 1, 'companyid' => $this->selectedcompany))) { // We have a company manager from another company. // We need to add another record. $company = new company($this->selectedcompany); $company->assign_user_to_company($adduser->id); $DB->set_field('company_users', 'managertype', 1, array('userid' => $adduser->id, 'companyid' => $this->selectedcompany)); // Deal with company courses. if ($companycourses = $DB->get_records('company_course', array('companyid' => $this->selectedcompany))) { foreach ($companycourses as $companycourse) { if ($DB->record_exists('course', array('id' => $companycourse->courseid))) { if ($DB->record_exists('company_created_courses', array('companyid' => $companycourse->companyid, 'courseid' => $companycourse->courseid))) { company_user::enrol($adduser, array($companycourse->courseid), $companycourse->companyid, $companycourseeditorrole->id); } else { company_user::enrol($adduser, array($companycourse->courseid), $companycourse->companyid, $companycoursenoneditorrole->id); } } } } } else { // Assign the user to department as staff. company::assign_user_to_department($departmentid, $adduser->id); } } } else { // Assign the user to department as staff. company::assign_user_to_department($departmentid, $adduser->id); } } } $this->potentialusers->invalidate_selected_users(); $this->currentusers->invalidate_selected_users(); } } // Process incoming unassignments. if (optional_param('remove', false, PARAM_BOOL) && confirm_sesskey()) { $userstounassign = $this->currentusers->get_selected_users(); if (!empty($userstounassign)) { // Check if we are mearly removing the manager role. if ($roletype != 0) { foreach ($userstounassign as $removeuser) { // GWL : Check the userid is valid. if (!company::check_valid_user($this->selectedcompany, $adduser->id, $this->departmentid)) { print_error('invaliduserdepartment', 'block_iomad_company_management'); } $userrecord = $DB->get_record('company_users', array('companyid' => $this->selectedcompany, 'userid' => $removeuser->id)); // Is this a manager from another company? if ($DB->get_records_sql("SELECT id FROM {company_users}\n WHERE userid = :userid\n AND companyid != :companyid\n AND managertype = 1", array('userid' => $removeuser->id, 'companyid' => $this->selectedcompany))) { // Remove the user from this company. $DB->delete_records('company_users', (array) $userrecord); } else { // Remove the manager status from the user. $userrecord->managertype = 0; $DB->update_record('company_users', $userrecord); role_unassign($companymanagerrole->id, $removeuser->id, $this->context->id); role_unassign($departmentmanagerrole->id, $removeuser->id, $this->context->id); } // Remove their capabilities from the company courses. if ($companycourses = $DB->get_records('company_course', array('companyid' => $this->selectedcompany))) { foreach ($companycourses as $companycourse) { if ($DB->record_exists('course', array('id' => $companycourse->courseid))) { company_user::unenrol($removeuser, array($companycourse->courseid), $companycourse->companyid); } } } } } else { foreach ($userstounassign as $removeuser) { // GWL : Check the userid is valid. if (!company::check_valid_user($this->selectedcompany, $removeuser->id, $this->departmentid)) { print_error('invaliduserdepartment', 'block_iomad_company_management'); } // Assign the user to parent department as staff. company::assign_user_to_department($this->companydepartment, $removeuser->id); } } $this->potentialusers->invalidate_selected_users(); $this->currentusers->invalidate_selected_users(); } } }
/** * function that deletes a role and cleanups up after it * @param roleid - id of role to delete * @return success */ function delete_role($roleid) { global $CFG, $USER; $success = true; // mdl 10149, check if this is the last active admin role // if we make the admin role not deletable then this part can go $systemcontext = get_context_instance(CONTEXT_SYSTEM); if ($role = get_record('role', 'id', $roleid)) { if (record_exists('role_capabilities', 'contextid', $systemcontext->id, 'roleid', $roleid, 'capability', 'moodle/site:doanything')) { // deleting an admin role $status = false; if ($adminroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, $systemcontext)) { foreach ($adminroles as $adminrole) { if ($adminrole->id != $roleid) { // some other admin role if (record_exists('role_assignments', 'roleid', $adminrole->id, 'contextid', $systemcontext->id)) { // found another admin role with at least 1 user assigned $status = true; break; } } } } if ($status !== true) { error('You can not delete this role because there is no other admin roles with users assigned'); } } } // first unssign all users if (!role_unassign($roleid)) { debugging("Error while unassigning all users from role with ID {$roleid}!"); $success = false; } // cleanup all references to this role, ignore errors if ($success) { // MDL-10679 find all contexts where this role has an override $contexts = get_records_sql("SELECT contextid, contextid\n FROM {$CFG->prefix}role_capabilities\n WHERE roleid = {$roleid}"); delete_records('role_capabilities', 'roleid', $roleid); delete_records('role_allow_assign', 'roleid', $roleid); delete_records('role_allow_assign', 'allowassign', $roleid); delete_records('role_allow_override', 'roleid', $roleid); delete_records('role_allow_override', 'allowoverride', $roleid); delete_records('role_names', 'roleid', $roleid); } // finally delete the role itself // get this before the name is gone for logging $rolename = get_field('role', 'name', 'id', $roleid); if ($success and !delete_records('role', 'id', $roleid)) { debugging("Could not delete role record with ID {$roleid}!"); $success = false; } if ($success) { add_to_log(SITEID, 'role', 'delete', 'admin/roles/action=delete&roleid=' . $roleid, $rolename, '', $USER->id); } return $success; }
/** * Sync roles for this user * * @param $user object user object (without system magic quotes) */ function sync_roles($user) { $iscreator = $this->iscreator($user->username); if ($iscreator === null) { return; // Nothing to sync - creators not configured } if ($roles = get_archetype_roles('coursecreator')) { $creatorrole = array_shift($roles); // We can only use one, let's use the first one $systemcontext = context_system::instance(); if ($iscreator) { // Following calls will not create duplicates role_assign($creatorrole->id, $user->id, $systemcontext->id, $this->roleauth); } else { // Unassign only if previously assigned by this plugin! role_unassign($creatorrole->id, $user->id, $systemcontext->id, $this->roleauth); } } }
/** * Removes a teacher from a given course (or ALL courses) * Does not delete the user account * * @param int $courseid The id of the course that is being viewed, if any * @param int $userid The id of the user that is being tested against. * @return bool */ function remove_teacher($userid, $courseid = 0) { global $CFG; $roles = get_roles_with_capability('moodle/legacy:editingteacher', CAP_ALLOW); if ($roles) { $roles += get_roles_with_capability('moodle/legacy:teacher', CAP_ALLOW); } else { $roles = get_roles_with_capability('moodle/legacy:teacher', CAP_ALLOW); } if (empty($roles)) { return true; } $return = true; if ($courseid) { if (!($context = get_context_instance(CONTEXT_COURSE, $courseid))) { return false; } /// First delete any crucial stuff that might still send mail if ($forums = get_records('forum', 'course', $courseid)) { foreach ($forums as $forum) { delete_records('forum_subscriptions', 'forum', $forum->id, 'userid', $userid); } } /// No need to remove from groups now foreach ($roles as $role) { // Unassign them from all the teacher roles $newreturn = role_unassign($role->id, $userid, 0, $context->id); if (empty($newreturn)) { $return = false; } } } else { delete_records('forum_subscriptions', 'userid', $userid); $return = true; foreach ($roles as $role) { // Unassign them from all the teacher roles $newreturn = role_unassign($role->id, $userid, 0, 0); if (empty($newreturn)) { $return = false; } } } return $return; }
/** * function that deletes a role and cleanups up after it * @param roleid - id of role to delete * @return success */ function delete_role($roleid) { global $CFG, $DB; $success = true; // mdl 10149, check if this is the last active admin role // if we make the admin role not deletable then this part can go $systemcontext = get_context_instance(CONTEXT_SYSTEM); if ($role = $DB->get_record('role', array('id' => $roleid))) { if ($DB->record_exists('role_capabilities', array('contextid' => $systemcontext->id, 'roleid' => $roleid, 'capability' => 'moodle/site:doanything'))) { // deleting an admin role $status = false; if ($adminroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, $systemcontext)) { foreach ($adminroles as $adminrole) { if ($adminrole->id != $roleid) { // some other admin role if ($DB->record_exists('role_assignments', array('roleid' => $adminrole->id, 'contextid' => $systemcontext->id))) { // found another admin role with at least 1 user assigned $status = true; break; } } } } if ($status !== true) { print_error('cannotdeleterolenoadmin', 'access'); } } } // first unssign all users if (!role_unassign($roleid)) { debugging("Error while unassigning all users from role with ID {$roleid}!"); $success = false; } // cleanup all references to this role, ignore errors if ($success) { $DB->delete_records('role_capabilities', array('roleid' => $roleid)); $DB->delete_records('role_allow_assign', array('roleid' => $roleid)); $DB->delete_records('role_allow_assign', array('allowassign' => $roleid)); $DB->delete_records('role_allow_override', array('roleid' => $roleid)); $DB->delete_records('role_allow_override', array('allowoverride' => $roleid)); $DB->delete_records('role_names', array('roleid' => $roleid)); $DB->delete_records('role_context_levels', array('roleid' => $roleid)); } // finally delete the role itself // get this before the name is gone for logging $rolename = $DB->get_field('role', 'name', array('id' => $roleid)); if ($success and !$DB->delete_records('role', array('id' => $roleid))) { debugging("Could not delete role record with ID {$roleid}!"); $success = false; } if ($success) { add_to_log(SITEID, 'role', 'delete', 'admin/roles/action=delete&roleid=' . $roleid, $rolename, ''); } return $success; }
/** * Forces synchronisation of all enrolments with external database. * * @param bool $verbose * @return int 0 means success, 1 db connect failure, 2 db read failure */ public function sync_enrolments($verbose = false) { 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')) { if ($verbose) { mtrace('User enrolment synchronisation skipped.'); } return 0; } if ($verbose) { mtrace('Starting user enrolment synchronisation...'); } if (!($extdb = $this->db_init())) { mtrace('Error while communicating with external enrolment database'); return 1; } // we may need a lot of memory here @set_time_limit(0); raise_memory_limit(MEMORY_HUGE); // 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'); $localcoursefield = $this->get_config('localcoursefield'); $unenrolaction = $this->get_config('unenrolaction'); $defaultrole = $this->get_config('defaultrole'); // create roles mapping $allroles = get_all_roles(); if (!isset($allroles[$defaultrole])) { $defaultrole = 0; } $roles = array(); foreach ($allroles as $role) { $roles[$role->{$localrolefield}] = $role->id; } // get a list of courses to be synced that are in external table $externalcourses = array(); $sql = $this->db_get_sql($table, array(), array($coursefield), true); if ($rs = $extdb->Execute($sql)) { if (!$rs->EOF) { while ($mapping = $rs->FetchRow()) { $mapping = reset($mapping); $mapping = $this->db_decode($mapping); if (empty($mapping)) { // invalid mapping continue; } $externalcourses[$mapping] = true; } } $rs->Close(); } else { mtrace('Error reading data from the external enrolment table'); $extdb->Close(); return 2; } $preventfullunenrol = empty($externalcourses); if ($preventfullunenrol and $unenrolaction == ENROL_EXT_REMOVED_UNENROL) { mtrace(' Preventing unenrolment of all current users, because it might result in major data loss, there has to be at least one record in external enrol table, sorry.'); } // first find all existing courses with enrol instance $existing = array(); $sql = "SELECT c.id, c.visible, c.{$localcoursefield} AS mapping, e.id AS enrolid, c.shortname\n FROM {course} c\n JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')"; $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 $params = array(); $localnotempty = ""; if ($localcoursefield !== 'id') { $localnotempty = "AND c.{$localcoursefield} <> :lcfe"; $params['lcfe'] = $DB->sql_empty(); } $sql = "SELECT c.id, c.visible, c.{$localcoursefield} AS mapping, c.shortname\n FROM {course} c\n LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')\n WHERE e.id IS NULL {$localnotempty}"; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $course) { if (empty($course->mapping)) { continue; } if (!isset($externalcourses[$course->mapping])) { // course not synced continue; } if (isset($existing[$course->mapping])) { // some duplicate, sorry continue; } $course->enrolid = $this->add_instance($course); $existing[$course->mapping] = $course; } $rs->close(); // free memory unset($externalcourses); // sync enrolments $ignorehidden = $this->get_config('ignorehiddencourses'); $sqlfields = array($userfield); if ($rolefield) { $sqlfields[] = $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\n FROM {user} u\n JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid)\n JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.itemid = ue.enrolid AND ra.component = 'enrol_database')\n 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), $sqlfields); 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 { mtrace('Error while communicating with external enrolment database'); $extdb->Close(); return; } unset($user_mapping); // enrol all users and sync roles foreach ($requested_roles as $userid => $userroles) { foreach ($userroles as $roleid) { if (empty($current_roles[$userid])) { $this->enrol_user($instance, $userid, $roleid, 0, 0, ENROL_USER_ACTIVE); $current_roles[$userid][$roleid] = $roleid; $current_status[$userid] = ENROL_USER_ACTIVE; if ($verbose) { mtrace(" enrolling: {$userid} ==> {$course->shortname} as " . $allroles[$roleid]->shortname); } } } // assign extra roles foreach ($userroles as $roleid) { if (empty($current_roles[$userid][$roleid])) { role_assign($roleid, $userid, $context->id, 'enrol_database', $instance->id); $current_roles[$userid][$roleid] = $roleid; if ($verbose) { mtrace(" assigning roles: {$userid} ==> {$course->shortname} as " . $allroles[$roleid]->shortname); } } } // unassign removed roles foreach ($current_roles[$userid] as $cr) { if (empty($userroles[$cr])) { role_unassign($cr, $userid, $context->id, 'enrol_database', $instance->id); unset($current_roles[$userid][$cr]); if ($verbose) { mtrace(" unsassigning roles: {$userid} ==> {$course->shortname}"); } } } // reenable enrolment when previously disable enrolment refreshed if ($current_status[$userid] == ENROL_USER_SUSPENDED) { $this->update_user_enrol($instance, $userid, ENROL_USER_ACTIVE); if ($verbose) { mtrace(" unsuspending: {$userid} ==> {$course->shortname}"); } } } // deal with enrolments removed from external table if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) { if (!$preventfullunenrol) { // unenrol foreach ($current_status as $userid => $status) { if (isset($requested_roles[$userid])) { continue; } $this->unenrol_user($instance, $userid); if ($verbose) { mtrace(" unenrolling: {$userid} ==> {$course->shortname}"); } } } } else { if ($unenrolaction == ENROL_EXT_REMOVED_KEEP) { // keep - only adding enrolments } else { if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND or $unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) { // disable foreach ($current_status as $userid => $status) { if (isset($requested_roles[$userid])) { continue; } if ($status != ENROL_USER_SUSPENDED) { $this->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED); if ($verbose) { mtrace(" suspending: {$userid} ==> {$course->shortname}"); } } if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) { role_unassign_all(array('contextid' => $context->id, 'userid' => $userid, 'component' => 'enrol_database', 'itemid' => $instance->id)); if ($verbose) { mtrace(" unsassigning all roles: {$userid} ==> {$course->shortname}"); } } } } } } } // close db connection $extdb->Close(); if ($verbose) { mtrace('...user enrolment synchronisation finished.'); } return 0; }
// checks permissions specified in settings.php if ($action === 'delete') { $contextlevel = required_param('contextlevel', PARAM_INT); $roleid = required_param('roleid', PARAM_INT); $confirm = optional_param('confirm', 0, PARAM_BOOL); $role = $DB->get_record('role', array('id' => $roleid), '*', MUST_EXIST); if ($confirm and confirm_sesskey()) { $sql = "SELECT ra.*\n FROM {role_assignments} ra\n JOIN {context} c ON c.id = ra.contextid\n LEFT JOIN {role_context_levels} rcl ON (rcl.roleid = ra.roleid AND rcl.contextlevel = c.contextlevel)\n WHERE rcl.id IS NULL AND ra.roleid = :roleid AND c.contextlevel = :contextlevel"; $ras = $DB->get_records_sql($sql, array('roleid' => $roleid, 'contextlevel' => $contextlevel)); foreach ($ras as $ra) { if (!empty($ra->component)) { //bad luck, we can not mess with plugin ras! //TODO: explain why not possible to remove ras continue; } role_unassign($ra->roleid, $ra->userid, $ra->contextid); } redirect($PAGE->url); } //show confirmation echo $OUTPUT->header(); $yesurl = new moodle_url($PAGE->url, array('roleid' => $roleid, 'contextlevel' => $contextlevel, 'action' => 'delete', 'confirm' => 1, 'sesskey' => sesskey())); $levelname = get_contextlevel_name($contextlevel); $rolename = format_string($role->name); $message = get_string('confirmdelete', 'tool_unsuproles', array('level' => $levelname, 'role' => $rolename)); echo $OUTPUT->confirm($message, $yesurl, $PAGE->url); echo $OUTPUT->footer(); die; } echo $OUTPUT->header(); echo $OUTPUT->heading(get_string('pluginname', 'tool_unsuproles'));
public function test_sync() { global $CFG, $DB; $this->resetAfterTest(true); $metalplugin = enrol_get_plugin('meta'); $manplugin = enrol_get_plugin('manual'); $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $user3 = $this->getDataGenerator()->create_user(); $user4 = $this->getDataGenerator()->create_user(); $user5 = $this->getDataGenerator()->create_user(); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $course3 = $this->getDataGenerator()->create_course(); $course4 = $this->getDataGenerator()->create_course(); $manual1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST); $manual2 = $DB->get_record('enrol', array('courseid' => $course2->id, 'enrol' => 'manual'), '*', MUST_EXIST); $manual3 = $DB->get_record('enrol', array('courseid' => $course3->id, 'enrol' => 'manual'), '*', MUST_EXIST); $manual4 = $DB->get_record('enrol', array('courseid' => $course4->id, 'enrol' => 'manual'), '*', MUST_EXIST); $student = $DB->get_record('role', array('shortname' => 'student')); $teacher = $DB->get_record('role', array('shortname' => 'teacher')); $manager = $DB->get_record('role', array('shortname' => 'manager')); $this->disable_plugin(); $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id); $this->getDataGenerator()->enrol_user($user2->id, $course1->id, $student->id); $this->getDataGenerator()->enrol_user($user3->id, $course1->id, 0); $this->getDataGenerator()->enrol_user($user4->id, $course1->id, $teacher->id); $this->getDataGenerator()->enrol_user($user5->id, $course1->id, $manager->id); $this->getDataGenerator()->enrol_user($user1->id, $course2->id, $student->id); $this->getDataGenerator()->enrol_user($user2->id, $course2->id, $teacher->id); $this->assertEquals(7, $DB->count_records('user_enrolments')); $this->assertEquals(6, $DB->count_records('role_assignments')); set_config('syncall', 0, 'enrol_meta'); set_config('nosyncroleids', $manager->id, 'enrol_meta'); require_once $CFG->dirroot . '/enrol/meta/locallib.php'; enrol_meta_sync(null, false); $this->assertEquals(7, $DB->count_records('user_enrolments')); $this->assertEquals(6, $DB->count_records('role_assignments')); $this->enable_plugin(); enrol_meta_sync(null, false); $this->assertEquals(7, $DB->count_records('user_enrolments')); $this->assertEquals(6, $DB->count_records('role_assignments')); // Disable the plugin to prevent add_instance from calling enrol_meta_sync. $this->disable_plugin(); $e1 = $metalplugin->add_instance($course3, array('customint1' => $course1->id)); $e2 = $metalplugin->add_instance($course3, array('customint1' => $course2->id)); $e3 = $metalplugin->add_instance($course4, array('customint1' => $course2->id)); $enrol1 = $DB->get_record('enrol', array('id' => $e1)); $enrol2 = $DB->get_record('enrol', array('id' => $e2)); $enrol3 = $DB->get_record('enrol', array('id' => $e3)); $this->enable_plugin(); enrol_meta_sync($course4->id, false); $this->assertEquals(9, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, $student)); $this->assertTrue($this->is_meta_enrolled($user2, $enrol3, $teacher)); enrol_meta_sync(null, false); $this->assertEquals(14, $DB->count_records('user_enrolments')); $this->assertEquals(13, $DB->count_records('role_assignments')); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); $this->assertTrue($this->is_meta_enrolled($user2, $enrol1, $student)); $this->assertFalse($this->is_meta_enrolled($user3, $enrol1)); $this->assertTrue($this->is_meta_enrolled($user4, $enrol1, $teacher)); $this->assertFalse($this->is_meta_enrolled($user5, $enrol1)); $this->assertTrue($this->is_meta_enrolled($user1, $enrol2, $student)); $this->assertTrue($this->is_meta_enrolled($user2, $enrol2, $teacher)); $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, $student)); $this->assertTrue($this->is_meta_enrolled($user2, $enrol3, $teacher)); set_config('syncall', 1, 'enrol_meta'); enrol_meta_sync(null, false); $this->assertEquals(16, $DB->count_records('user_enrolments')); $this->assertEquals(13, $DB->count_records('role_assignments')); $this->assertTrue($this->is_meta_enrolled($user3, $enrol1, false)); $this->assertTrue($this->is_meta_enrolled($user5, $enrol1, false)); $this->assertEquals(16, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->disable_plugin(); $manplugin->unenrol_user($manual1, $user1->id); $manplugin->unenrol_user($manual2, $user1->id); $this->assertEquals(14, $DB->count_records('user_enrolments')); $this->assertEquals(11, $DB->count_records('role_assignments')); $this->assertEquals(14, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->enable_plugin(); set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPEND, 'enrol_meta'); enrol_meta_sync($course4->id, false); $this->assertEquals(14, $DB->count_records('user_enrolments')); $this->assertEquals(11, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, $student)); $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid' => $enrol3->id, 'status' => ENROL_USER_SUSPENDED, 'userid' => $user1->id))); enrol_meta_sync(null, false); $this->assertEquals(14, $DB->count_records('user_enrolments')); $this->assertEquals(11, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid' => $enrol1->id, 'status' => ENROL_USER_SUSPENDED, 'userid' => $user1->id))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol2, $student)); $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid' => $enrol2->id, 'status' => ENROL_USER_SUSPENDED, 'userid' => $user1->id))); set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES, 'enrol_meta'); enrol_meta_sync($course4->id, false); $this->assertEquals(14, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, false)); $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid' => $enrol3->id, 'status' => ENROL_USER_SUSPENDED, 'userid' => $user1->id))); enrol_meta_sync(null, false); $this->assertEquals(14, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false)); $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid' => $enrol1->id, 'status' => ENROL_USER_SUSPENDED, 'userid' => $user1->id))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol2, false)); $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid' => $enrol2->id, 'status' => ENROL_USER_SUSPENDED, 'userid' => $user1->id))); set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL, 'enrol_meta'); enrol_meta_sync($course4->id, false); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol3)); enrol_meta_sync(null, false); $this->assertEquals(11, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1)); $this->assertFalse($this->is_meta_enrolled($user1, $enrol2)); // Now try sync triggered by events. set_config('syncall', 1, 'enrol_meta'); $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); enrol_meta_sync(null, false); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); $manplugin->unenrol_user($manual1, $user1->id); $this->assertEquals(11, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1)); enrol_meta_sync(null, false); $this->assertEquals(11, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1)); $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 0); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false)); enrol_meta_sync(null, false); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false)); $manplugin->unenrol_user($manual1, $user1->id); $this->assertEquals(11, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1)); enrol_meta_sync(null, false); $this->assertEquals(11, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1)); set_config('syncall', 0, 'enrol_meta'); enrol_meta_sync(null, false); $this->assertEquals(9, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(9, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1)); $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 0); $this->assertEquals(10, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(10, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student)); enrol_meta_sync(null, false); $this->assertEquals(10, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(10, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student)); role_assign($teacher->id, $user1->id, context_course::instance($course1->id)->id); $this->assertEquals(11, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $teacher)); enrol_meta_sync(null, false); $this->assertEquals(11, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $teacher)); role_unassign($teacher->id, $user1->id, context_course::instance($course1->id)->id); $this->assertEquals(10, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(10, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student)); enrol_meta_sync(null, false); $this->assertEquals(10, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(10, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student)); $manplugin->unenrol_user($manual1, $user1->id); $this->assertEquals(9, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(9, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertFalse($this->is_meta_enrolled($user1, $enrol1)); set_config('syncall', 1, 'enrol_meta'); set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPEND, 'enrol_meta'); enrol_meta_sync(null, false); $this->assertEquals(11, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); enrol_meta_sync(null, false); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); $manplugin->update_user_enrol($manual1, $user1->id, ENROL_USER_SUSPENDED); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); enrol_meta_sync(null, false); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); $manplugin->unenrol_user($manual1, $user1->id); $this->assertEquals(12, $DB->count_records('user_enrolments')); $this->assertEquals(9, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); enrol_meta_sync(null, false); $this->assertEquals(12, $DB->count_records('user_enrolments')); $this->assertEquals(9, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); enrol_meta_sync(null, false); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); set_config('syncall', 1, 'enrol_meta'); set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES, 'enrol_meta'); enrol_meta_sync(null, false); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); enrol_meta_sync(null, false); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); $manplugin->unenrol_user($manual1, $user1->id); $this->assertEquals(12, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false)); enrol_meta_sync(null, false); $this->assertEquals(12, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(11, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false)); $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); enrol_meta_sync(null, false); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student)); set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL, 'enrol_meta'); enrol_meta_sync(null, false); $this->assertEquals(13, $DB->count_records('user_enrolments')); $this->assertEquals(10, $DB->count_records('role_assignments')); $this->assertEquals(13, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); delete_course($course1, false); $this->assertEquals(3, $DB->count_records('user_enrolments')); $this->assertEquals(3, $DB->count_records('role_assignments')); $this->assertEquals(3, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); enrol_meta_sync(null, false); $this->assertEquals(3, $DB->count_records('user_enrolments')); $this->assertEquals(3, $DB->count_records('role_assignments')); $this->assertEquals(3, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); delete_course($course2, false); $this->assertEquals(0, $DB->count_records('user_enrolments')); $this->assertEquals(0, $DB->count_records('role_assignments')); $this->assertEquals(0, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); enrol_meta_sync(null, false); $this->assertEquals(0, $DB->count_records('user_enrolments')); $this->assertEquals(0, $DB->count_records('role_assignments')); $this->assertEquals(0, $DB->count_records('user_enrolments', array('status' => ENROL_USER_ACTIVE))); delete_course($course3, false); delete_course($course4, false); }
/** * This function will empty a course of user data. * It will retain the activities and the structure of the course. * @param object $data an object containing all the settings including courseid (without magic quotes) * @return array status array of array component, item, error */ function reset_course_userdata($data) { global $CFG, $USER; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/group/lib.php'; $data->courseid = $data->id; $context = get_context_instance(CONTEXT_COURSE, $data->courseid); // calculate the time shift of dates if (!empty($data->reset_start_date)) { // time part of course startdate should be zero $data->timeshift = $data->reset_start_date - usergetmidnight($data->reset_start_date_old); } else { $data->timeshift = 0; } // result array: component, item, error $status = array(); // start the resetting $componentstr = get_string('general'); // move the course start time if (!empty($data->reset_start_date) and $data->timeshift) { // change course start data set_field('course', 'startdate', $data->reset_start_date, 'id', $data->courseid); // update all course and group events - do not move activity events $updatesql = "UPDATE {$CFG->prefix}event\n SET timestart = timestart + ({$data->timeshift})\n WHERE courseid={$data->courseid} AND instance=0"; execute_sql($updatesql, false); $status[] = array('component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false); } if (!empty($data->reset_logs)) { delete_records('log', 'course', $data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deletelogs'), 'error' => false); } if (!empty($data->reset_events)) { delete_records('event', 'courseid', $data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deleteevents', 'calendar'), 'error' => false); } if (!empty($data->reset_notes)) { require_once $CFG->dirroot . '/notes/lib.php'; note_delete_all($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deletenotes', 'notes'), 'error' => false); } $componentstr = get_string('roles'); if (!empty($data->reset_roles_overrides)) { $children = get_child_contexts($context); foreach ($children as $child) { delete_records('role_capabilities', 'contextid', $child->id); } delete_records('role_capabilities', 'contextid', $context->id); //force refresh for logged in users mark_context_dirty($context->path); $status[] = array('component' => $componentstr, 'item' => get_string('deletecourseoverrides', 'role'), 'error' => false); } if (!empty($data->reset_roles_local)) { $children = get_child_contexts($context); foreach ($children as $child) { role_unassign(0, 0, 0, $child->id); } //force refresh for logged in users mark_context_dirty($context->path); $status[] = array('component' => $componentstr, 'item' => get_string('deletelocalroles', 'role'), 'error' => false); } // 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 (!has_capability('moodle/course:view', $context, $user->id)) { $data->unenrolled[$user->id] = $user->id; } } } } } if (!empty($data->unenrolled)) { $status[] = array('component' => $componentstr, 'item' => get_string('unenrol') . ' (' . count($data->unenrolled) . ')', 'error' => false); } $componentstr = get_string('groups'); // remove all group members if (!empty($data->reset_groups_members)) { groups_delete_group_members($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removegroupsmembers', 'group'), 'error' => false); } // remove all groups if (!empty($data->reset_groups_remove)) { groups_delete_groups($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroups', 'group'), 'error' => false); } // remove all grouping members if (!empty($data->reset_groupings_members)) { groups_delete_groupings_groups($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('removegroupingsmembers', 'group'), 'error' => false); } // remove all groupings if (!empty($data->reset_groupings_remove)) { groups_delete_groupings($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroupings', 'group'), 'error' => false); } // Look in every instance of every module for data to delete $unsupported_mods = array(); if ($allmods = get_records('modules')) { foreach ($allmods as $mod) { $modname = $mod->name; if (!count_records($modname, 'course', $data->courseid)) { continue; // skip mods with no instances } $modfile = $CFG->dirroot . '/mod/' . $modname . '/lib.php'; $moddeleteuserdata = $modname . '_reset_userdata'; // Function to delete user data if (file_exists($modfile)) { include_once $modfile; if (function_exists($moddeleteuserdata)) { $modstatus = $moddeleteuserdata($data); if (is_array($modstatus)) { $status = array_merge($status, $modstatus); } else { debugging('Module ' . $modname . ' returned incorrect staus - must be an array!'); } } else { $unsupported_mods[] = $mod; } } else { debugging('Missing lib.php in ' . $modname . ' module!'); } } } // mention unsupported mods if (!empty($unsupported_mods)) { foreach ($unsupported_mods as $mod) { $status[] = array('component' => get_string('modulenameplural', $mod->name), 'item' => '', 'error' => get_string('resetnotimplemented')); } } $componentstr = get_string('gradebook', 'grades'); // reset gradebook if (!empty($data->reset_gradebook_items)) { remove_course_grades($data->courseid, false); grade_grab_course_grades($data->courseid); grade_regrade_final_grades($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removeallcourseitems', 'grades'), 'error' => false); } else { if (!empty($data->reset_gradebook_grades)) { grade_course_reset($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removeallcoursegrades', 'grades'), 'error' => false); } } return $status; }
/** * Removes an assigned role from a user. * * @global moodle_database $DB * @param int $userid * @param int $roleid * @return bool */ public function unassign_role_from_user($userid, $roleid) { global $DB; // Admins may unassign any role, others only those they could assign. if (!is_siteadmin() and !array_key_exists($roleid, $this->get_assignable_roles())) { if (defined('AJAX_SCRIPT')) { throw new moodle_exception('invalidrole'); } return false; } $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST); $ras = $DB->get_records('role_assignments', array('contextid' => $this->context->id, 'userid' => $user->id, 'roleid' => $roleid)); foreach ($ras as $ra) { if ($ra->component) { if (strpos($ra->component, 'enrol_') !== 0) { continue; } if (!($plugin = enrol_get_plugin(substr($ra->component, 6)))) { continue; } if ($plugin->roles_protected()) { continue; } } role_unassign($ra->roleid, $ra->userid, $ra->contextid, $ra->component, $ra->itemid); } return true; }
/** * Removes an assigned role from a user. * * @global moodle_database $DB * @param int $userid * @param int $roleid * @return bool */ public function unassign_role_from_user($userid, $roleid) { global $DB; require_capability('moodle/role:assign', $this->context); $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST); try { role_unassign($roleid, $user->id, $this->context->id, '', NULL); } catch (Exception $e) { if (defined('AJAX_SCRIPT')) { throw $e; } return false; } return true; }
} $potentialuserselector->invalidate_selected_users(); $currentuserselector->invalidate_selected_users(); $rolename = $assignableroles[$roleid]; add_to_log($course->id, 'role', 'assign', 'mod/adobeconnect/participant.php?contextid=' . $context->id . '&roleid=' . $roleid, $rolename, '', $USER->id); // Counts have changed, so reload. list($assignableroles, $assigncounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_BOTH, true); } } // 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) { //unassign only roles that are added manually, no messing with other components!!! role_unassign($roleid, $removeuser->id, $context->id, ''); } $potentialuserselector->invalidate_selected_users(); $currentuserselector->invalidate_selected_users(); $rolename = $assignableroles[$roleid]; add_to_log($course->id, 'role', 'unassign', 'mod/adobeconnect/participant.php?contextid=' . $context->id . '&roleid=' . $roleid, $rolename, '', $USER->id); // Counts have changed, so reload. list($assignableroles, $assigncounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_BOTH, true); } } } $PAGE->set_pagelayout('admin'); $PAGE->set_title($title); switch ($context->contextlevel) { case CONTEXT_SYSTEM: admin_externalpage_setup('assignroles', '', array('contextid' => $contextid, 'roleid' => $roleid));
/** * Sync all meta course links. * * @param int $courseid one course, empty mean all * @param bool $verbose verbose CLI output * @return int 0 means ok, 1 means error, 2 means plugin disabled */ public function sync($courseid = null, $verbose = false) { global $DB; if (!enrol_is_enabled('self')) { return 2; } // Unfortunately this may take a long time, execution can be interrupted safely here. @set_time_limit(0); raise_memory_limit(MEMORY_HUGE); if ($verbose) { mtrace('Verifying self-enrolments...'); } $params = array('now' => time(), 'useractive' => ENROL_USER_ACTIVE, 'courselevel' => CONTEXT_COURSE); $coursesql = ""; if ($courseid) { $coursesql = "AND e.courseid = :courseid"; $params['courseid'] = $courseid; } // Note: the logic of self enrolment guarantees that user logged in at least once (=== u.lastaccess set) // and that user accessed course at least once too (=== user_lastaccess record exists). // First deal with users that did not log in for a really long time - they do not have user_lastaccess records. $sql = "SELECT e.*, ue.userid\n FROM {user_enrolments} ue\n JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'self' AND e.customint2 > 0)\n JOIN {user} u ON u.id = ue.userid\n WHERE :now - u.lastaccess > e.customint2\n {$coursesql}"; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $instance) { $userid = $instance->userid; unset($instance->userid); $this->unenrol_user($instance, $userid); if ($verbose) { $days = $instance->customint2 / 60 * 60 * 24; mtrace(" unenrolling user {$userid} from course {$instance->courseid} as they have did not log in for at least {$days} days"); } } $rs->close(); // Now unenrol from course user did not visit for a long time. $sql = "SELECT e.*, ue.userid\n FROM {user_enrolments} ue\n JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'self' AND e.customint2 > 0)\n JOIN {user_lastaccess} ul ON (ul.userid = ue.userid AND ul.courseid = e.courseid)\n WHERE :now - ul.timeaccess > e.customint2\n {$coursesql}"; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $instance) { $userid = $instance->userid; unset($instance->userid); $this->unenrol_user($instance, $userid); if ($verbose) { $days = $instance->customint2 / 60 * 60 * 24; mtrace(" unenrolling user {$userid} from course {$instance->courseid} as they have did not access course for at least {$days} days"); } } $rs->close(); // Deal with expired accounts. $action = $this->get_config('expiredaction', ENROL_EXT_REMOVED_KEEP); if ($action == ENROL_EXT_REMOVED_UNENROL) { $instances = array(); $sql = "SELECT ue.*, e.courseid, c.id AS contextid\n FROM {user_enrolments} ue\n JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'self')\n JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :courselevel)\n WHERE ue.timeend > 0 AND ue.timeend < :now\n {$coursesql}"; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $ue) { if (empty($instances[$ue->enrolid])) { $instances[$ue->enrolid] = $DB->get_record('enrol', array('id' => $ue->enrolid)); } $instance = $instances[$ue->enrolid]; if ($instance->roleid) { role_unassign($instance->roleid, $ue->userid, $ue->contextid, '', 0); } $this->unenrol_user($instance, $ue->userid); if ($verbose) { mtrace(" unenrolling expired user {$ue->userid} from course {$instance->courseid}"); } } $rs->close(); unset($instances); } else { if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES) { $instances = array(); $sql = "SELECT ue.*, e.courseid, c.id AS contextid\n FROM {user_enrolments} ue\n JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'self')\n JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :courselevel)\n WHERE ue.timeend > 0 AND ue.timeend < :now\n AND ue.status = :useractive\n {$coursesql}"; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $ue) { if (empty($instances[$ue->enrolid])) { $instances[$ue->enrolid] = $DB->get_record('enrol', array('id' => $ue->enrolid)); } $instance = $instances[$ue->enrolid]; if (1 == $DB->count_records('role_assignments', array('userid' => $ue->userid, 'contextid' => $ue->contextid))) { role_unassign_all(array('userid' => $ue->userid, 'contextid' => $ue->contextid, 'component' => '', 'itemid' => 0), true); } else { if ($instance->roleid) { role_unassign($instance->roleid, $ue->userid, $ue->contextid, '', 0); } } $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED); if ($verbose) { mtrace(" suspending expired user {$ue->userid} in course {$instance->courseid}"); } } $rs->close(); unset($instances); } else { // ENROL_EXT_REMOVED_KEEP means no changes. } } if ($verbose) { mtrace('...user self-enrolment updates finished.'); } return 0; }
/// Run all core cron jobs, but not every time since they aren't too important. /// These don't have a timer to reduce load, so we'll use a random number /// to randomly choose the percentage of times we should run these jobs. srand((double) microtime() * 10000000); $random100 = rand(0, 100); 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 = get_recordset_sql("SELECT id, userid, courseid\n FROM {$CFG->prefix}user_lastaccess\n WHERE courseid != " . SITEID . "\n AND timeaccess < {$cuttime} "); while ($assign = rs_fetch_next_record($rs)) { if ($context = get_context_instance(CONTEXT_COURSE, $assign->courseid)) { if (role_unassign(0, $assign->userid, 0, $context->id)) { mtrace("Deleted assignment for user {$assign->userid} from course {$assign->courseid}"); } } } rs_close($rs); /// Execute the same query again, looking for remaining records and deleting them /// if the user hasn't moodle/course:view in the CONTEXT_COURSE context (orphan records) $rs = get_recordset_sql("SELECT id, userid, courseid\n FROM {$CFG->prefix}user_lastaccess\n WHERE courseid != " . SITEID . "\n AND timeaccess < {$cuttime} "); while ($assign = rs_fetch_next_record($rs)) { if ($context = get_context_instance(CONTEXT_COURSE, $assign->courseid)) { if (!has_capability('moodle/course:view', $context, $assign->userid)) { delete_records('user_lastaccess', 'userid', $assign->userid, 'courseid', $assign->courseid); mtrace("Deleted orphan user_lastaccess for user {$assign->userid} from course {$assign->courseid}"); } }
/** * Unassign roles from users * * @param array $unassignments An array of unassignment */ public static function unassign_roles($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::unassign_roles_parameters(), array('unassignments' => $unassignments)); $transaction = $DB->start_delegated_transaction(); foreach ($params['unassignments'] as $unassignment) { // Ensure the current user is allowed to run this function in the unassignment context $context = self::get_context_from_params($unassignment); self::validate_context($context); require_capability('moodle/role:assign', $context); // throw an exception if user is not able to unassign the role in this context $roles = get_assignable_roles($context, ROLENAME_SHORT); if (!array_key_exists($unassignment['roleid'], $roles)) { throw new invalid_parameter_exception('Can not unassign roleid=' . $unassignment['roleid'] . ' in contextid=' . $unassignment['contextid']); } role_unassign($unassignment['roleid'], $unassignment['userid'], $context->id); } $transaction->allow_commit(); }
$topleveladmin = false; // we only worry about this if the role has doanything capability at site level if ($context->id == $sitecontext->id && ($adminroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, $sitecontext))) { foreach ($adminroles as $adminrole) { if ($adminrole->id == $roleid) { $topleveladmin = true; } } } foreach ($frm->removeselect as $removeuser) { $removeuser = clean_param($removeuser, PARAM_INT); if ($topleveladmin && $removeuser == $USER->id) { // Prevent unassigning oneself from being admin continue; } if (!role_unassign($roleid, $removeuser, 0, $context->id)) { $errors[] = "Could not remove user with id {$removeuser} from this role!"; } else { if ($inmeta) { sync_metacourse($courseid); $newroles = get_user_roles($context, $removeuser, false); if (!empty($newroles) and !array_key_exists($roleid, $newroles)) { $erruser = get_record('user', 'id', $removeuser, '', '', '', '', 'id, firstname, lastname'); $errors[] = get_string('metaunassignerror', 'role', fullname($erruser)); $allow = false; } } } } $rolename = get_field('role', 'name', 'id', $roleid); add_to_log($course->id, 'role', 'unassign', 'admin/roles/assign.php?contextid=' . $context->id . '&roleid=' . $roleid, $rolename, '', $USER->id);
/** * A small functional test of accesslib functions and classes. * @return void */ public function test_everything_in_accesslib() { global $USER, $SITE, $CFG, $DB, $ACCESSLIB_PRIVATE; $this->resetAfterTest(true); $generator = $this->getDataGenerator(); // Fill the site with some real data $testcategories = array(); $testcourses = array(); $testpages = array(); $testblocks = array(); $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id'); $systemcontext = context_system::instance(); $frontpagecontext = context_course::instance(SITEID); // Add block to system context $bi = $generator->create_block('online_users'); context_block::instance($bi->id); $testblocks[] = $bi->id; // Some users $testusers = array(); for($i=0; $i<20; $i++) { $user = $generator->create_user(); $testusers[$i] = $user->id; $usercontext = context_user::instance($user->id); // Add block to user profile $bi = $generator->create_block('online_users', array('parentcontextid'=>$usercontext->id)); $testblocks[] = $bi->id; } // Deleted user - should be ignored everywhere, can not have context $generator->create_user(array('deleted'=>1)); // Add block to frontpage $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagecontext->id)); $frontpageblockcontext = context_block::instance($bi->id); $testblocks[] = $bi->id; // Add a resource to frontpage $page = $generator->create_module('page', array('course'=>$SITE->id)); $testpages[] = $page->id; $frontpagepagecontext = context_module::instance($page->cmid); // Add block to frontpage resource $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagepagecontext->id)); $frontpagepageblockcontext = context_block::instance($bi->id); $testblocks[] = $bi->id; // Some nested course categories with courses $manualenrol = enrol_get_plugin('manual'); $parentcat = 0; for($i=0; $i<5; $i++) { $cat = $generator->create_category(array('parent'=>$parentcat)); $testcategories[] = $cat->id; $catcontext = context_coursecat::instance($cat->id); $parentcat = $cat->id; if ($i >=4) { continue; } // Add resource to each category $bi = $generator->create_block('online_users', array('parentcontextid'=>$catcontext->id)); context_block::instance($bi->id); // Add a few courses to each category for($j=0; $j<6; $j++) { $course = $generator->create_course(array('category'=>$cat->id)); $testcourses[] = $course->id; $coursecontext = context_course::instance($course->id); if ($j >= 5) { continue; } // Add manual enrol instance $manualenrol->add_default_instance($DB->get_record('course', array('id'=>$course->id))); // Add block to each course $bi = $generator->create_block('online_users', array('parentcontextid'=>$coursecontext->id)); $testblocks[] = $bi->id; // Add a resource to each course $page = $generator->create_module('page', array('course'=>$course->id)); $testpages[] = $page->id; $modcontext = context_module::instance($page->cmid); // Add block to each module $bi = $generator->create_block('online_users', array('parentcontextid'=>$modcontext->id)); $testblocks[] = $bi->id; } } // Make sure all contexts were created properly $count = 1; //system $count += $DB->count_records('user', array('deleted'=>0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEquals($DB->count_records('context'), $count); $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0); $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0); // ====== context_helper::get_level_name() ================================ $levels = context_helper::get_all_levels(); foreach ($levels as $level=>$classname) { $name = context_helper::get_level_name($level); $this->assertFalse(empty($name)); } // ======= context::instance_by_id(), context_xxx::instance(); $context = context::instance_by_id($frontpagecontext->id); $this->assertSame($context->contextlevel, CONTEXT_COURSE); $this->assertFalse(context::instance_by_id(-1, IGNORE_MISSING)); try { context::instance_by_id(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $this->assertTrue(context_system::instance() instanceof context_system); $this->assertTrue(context_coursecat::instance($testcategories[0]) instanceof context_coursecat); $this->assertTrue(context_course::instance($testcourses[0]) instanceof context_course); $this->assertTrue(context_module::instance($testpages[0]) instanceof context_module); $this->assertTrue(context_block::instance($testblocks[0]) instanceof context_block); $this->assertFalse(context_coursecat::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_course::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_module::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_block::instance(-1, IGNORE_MISSING)); try { context_coursecat::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_course::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_module::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_block::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } // ======= $context->get_url(), $context->get_context_name(), $context->get_capabilities() ========= $testcontexts = array(); $testcontexts[CONTEXT_SYSTEM] = context_system::instance(); $testcontexts[CONTEXT_COURSECAT] = context_coursecat::instance($testcategories[0]); $testcontexts[CONTEXT_COURSE] = context_course::instance($testcourses[0]); $testcontexts[CONTEXT_MODULE] = context_module::instance($testpages[0]); $testcontexts[CONTEXT_BLOCK] = context_block::instance($testblocks[0]); foreach ($testcontexts as $context) { $name = $context->get_context_name(true, true); $this->assertFalse(empty($name)); $this->assertTrue($context->get_url() instanceof moodle_url); $caps = $context->get_capabilities(); $this->assertTrue(is_array($caps)); foreach ($caps as $cap) { $cap = (array)$cap; $this->assertSame(array_keys($cap), array('id', 'name', 'captype', 'contextlevel', 'component', 'riskbitmask')); } } unset($testcontexts); // ===== $context->get_course_context() ========================================= $this->assertFalse($systemcontext->get_course_context(false)); try { $systemcontext->get_course_context(); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $context = context_coursecat::instance($testcategories[0]); $this->assertFalse($context->get_course_context(false)); try { $context->get_course_context(); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $this->assertSame($frontpagecontext->get_course_context(true), $frontpagecontext); $this->assertSame($frontpagepagecontext->get_course_context(true), $frontpagecontext); $this->assertSame($frontpagepageblockcontext->get_course_context(true), $frontpagecontext); // ======= $context->get_parent_context(), $context->get_parent_contexts(), $context->get_parent_context_ids() ======= $userid = reset($testusers); $usercontext = context_user::instance($userid); $this->assertSame($usercontext->get_parent_context(), $systemcontext); $this->assertSame($usercontext->get_parent_contexts(), array($systemcontext->id=>$systemcontext)); $this->assertSame($usercontext->get_parent_contexts(true), array($usercontext->id=>$usercontext, $systemcontext->id=>$systemcontext)); $this->assertSame($systemcontext->get_parent_contexts(), array()); $this->assertSame($systemcontext->get_parent_contexts(true), array($systemcontext->id=>$systemcontext)); $this->assertSame($systemcontext->get_parent_context_ids(), array()); $this->assertSame($systemcontext->get_parent_context_ids(true), array($systemcontext->id)); $this->assertSame($frontpagecontext->get_parent_context(), $systemcontext); $this->assertSame($frontpagecontext->get_parent_contexts(), array($systemcontext->id=>$systemcontext)); $this->assertSame($frontpagecontext->get_parent_contexts(true), array($frontpagecontext->id=>$frontpagecontext, $systemcontext->id=>$systemcontext)); $this->assertSame($frontpagecontext->get_parent_context_ids(), array($systemcontext->id)); $this->assertEquals($frontpagecontext->get_parent_context_ids(true), array($frontpagecontext->id, $systemcontext->id)); $this->assertSame($systemcontext->get_parent_context(), false); $frontpagecontext = context_course::instance($SITE->id); $parent = $systemcontext; foreach ($testcategories as $catid) { $catcontext = context_coursecat::instance($catid); $this->assertSame($catcontext->get_parent_context(), $parent); $parent = $catcontext; } $this->assertSame($frontpagepagecontext->get_parent_context(), $frontpagecontext); $this->assertSame($frontpageblockcontext->get_parent_context(), $frontpagecontext); $this->assertSame($frontpagepageblockcontext->get_parent_context(), $frontpagepagecontext); // ====== $context->get_child_contexts() ================================ $CFG->debug = 0; $children = $systemcontext->get_child_contexts(); $CFG->debug = DEBUG_DEVELOPER; $this->assertEquals(count($children)+1, $DB->count_records('context')); $context = context_coursecat::instance($testcategories[3]); $children = $context->get_child_contexts(); $countcats = 0; $countcourses = 0; $countblocks = 0; foreach ($children as $child) { if ($child->contextlevel == CONTEXT_COURSECAT) { $countcats++; } if ($child->contextlevel == CONTEXT_COURSE) { $countcourses++; } if ($child->contextlevel == CONTEXT_BLOCK) { $countblocks++; } } $this->assertEquals(count($children), 8); $this->assertEquals($countcats, 1); $this->assertEquals($countcourses, 6); $this->assertEquals($countblocks, 1); $context = context_course::instance($testcourses[2]); $children = $context->get_child_contexts(); $this->assertEquals(count($children), 7); // depends on number of default blocks $context = context_module::instance($testpages[3]); $children = $context->get_child_contexts(); $this->assertEquals(count($children), 1); $context = context_block::instance($testblocks[1]); $children = $context->get_child_contexts(); $this->assertEquals(count($children), 0); unset($children); unset($countcats); unset($countcourses); unset($countblocks); // ======= context_helper::reset_caches() ============================ context_helper::reset_caches(); $this->assertEquals(context_inspection::test_context_cache_size(), 0); context_course::instance($SITE->id); $this->assertEquals(context_inspection::test_context_cache_size(), 1); // ======= context preloading ======================================== context_helper::reset_caches(); $sql = "SELECT ".context_helper::get_preload_record_columns_sql('c')." FROM {context} c WHERE c.contextlevel <> ".CONTEXT_SYSTEM; $records = $DB->get_records_sql($sql); $firstrecord = reset($records); $columns = context_helper::get_preload_record_columns('c'); $firstrecord = (array)$firstrecord; $this->assertSame(array_keys($firstrecord), array_values($columns)); context_helper::reset_caches(); foreach ($records as $record) { context_helper::preload_from_record($record); $this->assertEquals($record, new stdClass()); } $this->assertEquals(context_inspection::test_context_cache_size(), count($records)); unset($records); unset($columns); context_helper::reset_caches(); context_helper::preload_course($SITE->id); $this->assertEquals(7, context_inspection::test_context_cache_size()); // depends on number of default blocks // ====== assign_capability(), unassign_capability() ==================== $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertFalse($rc); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext->id); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertEquals($rc->permission, CAP_ALLOW); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext->id); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertEquals($rc->permission, CAP_ALLOW); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext, true); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertEquals($rc->permission, CAP_PREVENT); assign_capability('moodle/site:accessallgroups', CAP_INHERIT, $allroles['teacher'], $frontpagecontext); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertFalse($rc); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext); unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext, true); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertFalse($rc); unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext->id, true); unset($rc); accesslib_clear_all_caches(false); // must be done after assign_capability() // ======= role_assign(), role_unassign(), role_unassign_all() ============== $context = context_course::instance($testcourses[1]); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 0); role_assign($allroles['teacher'], $testusers[1], $context->id); role_assign($allroles['teacher'], $testusers[2], $context->id); role_assign($allroles['manager'], $testusers[1], $context->id); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 3); role_unassign($allroles['teacher'], $testusers[1], $context->id); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 2); role_unassign_all(array('contextid'=>$context->id)); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 0); unset($context); accesslib_clear_all_caches(false); // just in case // ====== has_capability(), get_users_by_capability(), role_switch(), reload_all_capabilities() and friends ======================== $adminid = get_admin()->id; $guestid = $CFG->siteguest; // Enrol some users into some courses $course1 = $DB->get_record('course', array('id'=>$testcourses[22]), '*', MUST_EXIST); $course2 = $DB->get_record('course', array('id'=>$testcourses[7]), '*', MUST_EXIST); $cms = $DB->get_records('course_modules', array('course'=>$course1->id), 'id'); $cm1 = reset($cms); $blocks = $DB->get_records('block_instances', array('parentcontextid'=>context_module::instance($cm1->id)->id), 'id'); $block1 = reset($blocks); $instance1 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course1->id)); $instance2 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course2->id)); for($i=0; $i<9; $i++) { $manualenrol->enrol_user($instance1, $testusers[$i], $allroles['student']); } $manualenrol->enrol_user($instance1, $testusers[8], $allroles['teacher']); $manualenrol->enrol_user($instance1, $testusers[9], $allroles['editingteacher']); for($i=10; $i<15; $i++) { $manualenrol->enrol_user($instance2, $testusers[$i], $allroles['student']); } $manualenrol->enrol_user($instance2, $testusers[15], $allroles['editingteacher']); // Add tons of role assignments - the more the better role_assign($allroles['coursecreator'], $testusers[11], context_coursecat::instance($testcategories[2])); role_assign($allroles['manager'], $testusers[12], context_coursecat::instance($testcategories[1])); role_assign($allroles['student'], $testusers[9], context_module::instance($cm1->id)); role_assign($allroles['teacher'], $testusers[8], context_module::instance($cm1->id)); role_assign($allroles['guest'], $testusers[13], context_course::instance($course1->id)); role_assign($allroles['teacher'], $testusers[7], context_block::instance($block1->id)); role_assign($allroles['manager'], $testusers[9], context_block::instance($block1->id)); role_assign($allroles['editingteacher'], $testusers[9], context_course::instance($course1->id)); role_assign($allroles['teacher'], $adminid, context_course::instance($course1->id)); role_assign($allroles['editingteacher'], $adminid, context_block::instance($block1->id)); // Add tons of overrides - the more the better assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpageblockcontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpageblockcontext, true); assign_capability('moodle/block:view', CAP_PROHIBIT, $allroles['guest'], $frontpageblockcontext, true); assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['user'], $frontpageblockcontext, true); assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['student'], $frontpageblockcontext, true); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $CFG->defaultuserroleid, $frontpagepagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagepagecontext, true); assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $frontpagepagecontext, true); assign_capability('mod/page:view', CAP_ALLOW, $allroles['user'], $frontpagepagecontext, true); assign_capability('moodle/page:view', CAP_ALLOW, $allroles['student'], $frontpagepagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext, true); assign_capability('mod/page:view', CAP_ALLOW, $allroles['guest'], $frontpagecontext, true); assign_capability('mod/page:view', CAP_PROHIBIT, $allroles['user'], $frontpagecontext, true); assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $systemcontext, true); accesslib_clear_all_caches(false); // must be done after assign_capability() // Extra tests for guests and not-logged-in users because they can not be verified by cross checking // with get_users_by_capability() where they are ignored $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, $guestid)); $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, $guestid)); $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, $guestid)); $this->assertFalse(has_capability('mod/page:view', $systemcontext, $guestid)); $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, 0)); $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, 0)); $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, 0)); $this->assertFalse(has_capability('mod/page:view', $systemcontext, 0)); $this->assertFalse(has_capability('moodle/course:create', $systemcontext, $testusers[11])); $this->assertTrue(has_capability('moodle/course:create', context_coursecat::instance($testcategories[2]), $testusers[11])); $this->assertFalse(has_capability('moodle/course:create', context_course::instance($testcourses[1]), $testusers[11])); $this->assertTrue(has_capability('moodle/course:create', context_course::instance($testcourses[19]), $testusers[11])); $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[1]), $testusers[9])); $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[19]), $testusers[9])); $this->assertFalse(has_capability('moodle/course:update', $systemcontext, $testusers[9])); // Test the list of enrolled users $coursecontext = context_course::instance($course1->id); $enrolled = get_enrolled_users($coursecontext); $this->assertEquals(count($enrolled), 10); for($i=0; $i<10; $i++) { $this->assertTrue(isset($enrolled[$testusers[$i]])); } $enrolled = get_enrolled_users($coursecontext, 'moodle/course:update'); $this->assertEquals(count($enrolled), 1); $this->assertTrue(isset($enrolled[$testusers[9]])); unset($enrolled); // role switching $userid = $testusers[9]; $USER = $DB->get_record('user', array('id'=>$userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); $this->assertFalse(is_role_switched($course1->id)); role_switch($allroles['student'], $coursecontext); $this->assertTrue(is_role_switched($course1->id)); $this->assertEquals($USER->access['rsw'][$coursecontext->path], $allroles['student']); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); role_switch(0, $coursecontext); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); $userid = $adminid; $USER = $DB->get_record('user', array('id'=>$userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $blockcontext = context_block::instance($block1->id); $this->assertTrue(has_capability('moodle/course:update', $blockcontext)); role_switch($allroles['student'], $coursecontext); $this->assertEquals($USER->access['rsw'][$coursecontext->path], $allroles['student']); $this->assertFalse(has_capability('moodle/course:update', $blockcontext)); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $blockcontext)); load_all_capabilities(); $this->assertTrue(has_capability('moodle/course:update', $blockcontext)); // temp course role for enrol $DB->delete_records('cache_flags', array()); // this prevents problem with dirty contexts immediately resetting the temp role - this is a known problem... $userid = $testusers[5]; $roleid = $allroles['editingteacher']; $USER = $DB->get_record('user', array('id'=>$userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); $this->assertFalse(isset($USER->access['ra'][$coursecontext->path][$roleid])); load_temp_course_role($coursecontext, $roleid); $this->assertEquals($USER->access['ra'][$coursecontext->path][$roleid], $roleid); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); remove_temp_course_roles($coursecontext); $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid)); load_temp_course_role($coursecontext, $roleid); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid)); $USER = new stdClass(); $USER->id = 0; // Now cross check has_capability() with get_users_by_capability(), each using different code paths, // they have to be kept in sync, usually only one of them breaks, so we know when something is wrong, // at the same time validate extra restrictions (guest read only no risks, admin exception, non existent and deleted users) $contexts = $DB->get_records('context', array(), 'id'); $contexts = array_values($contexts); $capabilities = $DB->get_records('capabilities', array(), 'id'); $capabilities = array_values($capabilities); $roles = array($allroles['guest'], $allroles['user'], $allroles['teacher'], $allroles['editingteacher'], $allroles['coursecreator'], $allroles['manager']); $userids = array_values($testusers); $userids[] = get_admin()->id; if (!PHPUNIT_LONGTEST) { $contexts = array_slice($contexts, 0, 10); $capabilities = array_slice($capabilities, 0, 5); $userids = array_slice($userids, 0, 5); } // Random time! //srand(666); foreach($userids as $userid) { // no guest or deleted // each user gets 0-10 random roles $rcount = rand(0, 10); for($j=0; $j<$rcount; $j++) { $roleid = $roles[rand(0, count($roles)-1)]; $contextid = $contexts[rand(0, count($contexts)-1)]->id; role_assign($roleid, $userid, $contextid); } } $permissions = array(CAP_ALLOW, CAP_PREVENT, CAP_INHERIT, CAP_PREVENT); $maxoverrides = count($contexts)*10; for($j=0; $j<$maxoverrides; $j++) { $roleid = $roles[rand(0, count($roles)-1)]; $contextid = $contexts[rand(0, count($contexts)-1)]->id; $permission = $permissions[rand(0,count($permissions)-1)]; $capname = $capabilities[rand(0, count($capabilities)-1)]->name; assign_capability($capname, $permission, $roleid, $contextid, true); } unset($permissions); unset($roles); accesslib_clear_all_caches(false); // must be done after assign_capability() // Test time - let's set up some real user, just in case the logic for USER affects the others... $USER = $DB->get_record('user', array('id'=>$testusers[3])); load_all_capabilities(); $userids[] = $CFG->siteguest; $userids[] = 0; // not-logged-in user $userids[] = -1; // non-existent user foreach ($contexts as $crecord) { $context = context::instance_by_id($crecord->id); if ($coursecontext = $context->get_course_context(false)) { $enrolled = get_enrolled_users($context); } else { $enrolled = array(); } foreach ($capabilities as $cap) { $allowed = get_users_by_capability($context, $cap->name, 'u.id, u.username'); if ($enrolled) { $enrolledwithcap = get_enrolled_users($context, $cap->name); } else { $enrolledwithcap = array(); } foreach ($userids as $userid) { if ($userid == 0 or isguestuser($userid)) { if ($userid == 0) { $CFG->forcelogin = true; $this->assertFalse(has_capability($cap->name, $context, $userid)); unset($CFG->forcelogin); } if (($cap->captype === 'write') or ($cap->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))) { $this->assertFalse(has_capability($cap->name, $context, $userid)); } $this->assertFalse(isset($allowed[$userid])); } else { if (is_siteadmin($userid)) { $this->assertTrue(has_capability($cap->name, $context, $userid, true)); } $hascap = has_capability($cap->name, $context, $userid, false); $this->assertSame($hascap, isset($allowed[$userid]), "Capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." "); if (isset($enrolled[$userid])) { $this->assertSame(isset($allowed[$userid]), isset($enrolledwithcap[$userid]), "Enrolment with capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." "); } } } } } // Back to nobody $USER = new stdClass(); $USER->id = 0; unset($contexts); unset($userids); unset($capabilities); // Now let's do all the remaining tests that break our carefully prepared fake site // ======= $context->mark_dirty() ======================================= $DB->delete_records('cache_flags', array()); accesslib_clear_all_caches(false); $systemcontext->mark_dirty(); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$systemcontext->path])); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$systemcontext->path])); // ======= $context->reload_if_dirty(); ================================= $DB->delete_records('cache_flags', array()); accesslib_clear_all_caches(false); load_all_capabilities(); $context = context_course::instance($testcourses[2]); $page = $DB->get_record('page', array('course'=>$testcourses[2])); $pagecontext = context_module::instance($page->id); $context->mark_dirty(); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path])); $USER->access['test'] = true; $context->reload_if_dirty(); $this->assertFalse(isset($USER->access['test'])); $context->mark_dirty(); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path])); $USER->access['test'] = true; $pagecontext->reload_if_dirty(); $this->assertFalse(isset($USER->access['test'])); // ======= context_helper::build_all_paths() ============================ $oldcontexts = $DB->get_records('context', array(), 'id'); $DB->set_field_select('context', 'path', NULL, "contextlevel <> ".CONTEXT_SYSTEM); $DB->set_field_select('context', 'depth', 0, "contextlevel <> ".CONTEXT_SYSTEM); context_helper::build_all_paths(); $newcontexts = $DB->get_records('context', array(), 'id'); $this->assertEquals($oldcontexts, $newcontexts); unset($oldcontexts); unset($newcontexts); // ======= $context->reset_paths() ====================================== $context = context_course::instance($testcourses[2]); $children = $context->get_child_contexts(); $context->reset_paths(false); $this->assertSame($DB->get_field('context', 'path', array('id'=>$context->id)), NULL); $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$context->id)), 0); foreach ($children as $child) { $this->assertSame($DB->get_field('context', 'path', array('id'=>$child->id)), NULL); $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$child->id)), 0); } $this->assertEquals(count($children)+1, $DB->count_records('context', array('depth'=>0))); $this->assertEquals(count($children)+1, $DB->count_records('context', array('path'=>NULL))); $context = context_course::instance($testcourses[2]); $context->reset_paths(true); $context = context_course::instance($testcourses[2]); $this->assertEquals($DB->get_field('context', 'path', array('id'=>$context->id)), $context->path); $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$context->id)), $context->depth); $this->assertEquals(0, $DB->count_records('context', array('depth'=>0))); $this->assertEquals(0, $DB->count_records('context', array('path'=>NULL))); // ====== $context->update_moved(); ====================================== accesslib_clear_all_caches(false); $DB->delete_records('cache_flags', array()); $course = $DB->get_record('course', array('id'=>$testcourses[0])); $context = context_course::instance($course->id); $oldpath = $context->path; $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}"); $categorycontext = context_coursecat::instance($miscid); $course->category = $miscid; $DB->update_record('course', $course); $context->update_moved($categorycontext); $context = context_course::instance($course->id); $this->assertEquals($context->get_parent_context(), $categorycontext); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$oldpath])); $this->assertTrue(isset($dirty[$context->path])); // ====== $context->delete_content() ===================================== context_helper::reset_caches(); $context = context_module::instance($testpages[3]); $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); $context->delete_content(); $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); // ====== $context->delete() ============================= context_helper::reset_caches(); $context = context_module::instance($testpages[4]); $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); $bi = $DB->get_record('block_instances', array('parentcontextid'=>$context->id)); $bicontext = context_block::instance($bi->id); $DB->delete_records('cache_flags', array()); $context->delete(); // should delete also linked blocks $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$context->path])); $this->assertFalse($DB->record_exists('context', array('id'=>$context->id))); $this->assertFalse($DB->record_exists('context', array('id'=>$bicontext->id))); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_MODULE, 'instanceid'=>$testpages[4]))); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK, 'instanceid'=>$bi->id))); $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); context_module::instance($testpages[4]); // ====== context_helper::delete_instance() ============================= context_helper::reset_caches(); $lastcourse = array_pop($testcourses); $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse))); $coursecontext = context_course::instance($lastcourse); $this->assertEquals(context_inspection::test_context_cache_size(), 1); $this->assertFalse($coursecontext->instanceid == CONTEXT_COURSE); $DB->delete_records('cache_flags', array()); context_helper::delete_instance(CONTEXT_COURSE, $lastcourse); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$coursecontext->path])); $this->assertEquals(context_inspection::test_context_cache_size(), 0); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse))); context_course::instance($lastcourse); // ======= context_helper::create_instances() ========================== $prevcount = $DB->count_records('context'); $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); context_helper::create_instances(null, true); $this->assertSame($DB->count_records('context'), $prevcount); $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0); $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0); $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); $DB->delete_records('block_instances', array()); $prevcount = $DB->count_records('context'); $DB->delete_records_select('context', 'contextlevel <> '.CONTEXT_SYSTEM); context_helper::create_instances(null, true); $this->assertSame($DB->count_records('context'), $prevcount); $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0); $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0); // ======= context_helper::cleanup_instances() ========================== $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}"); $DB->delete_records('course', array('id'=>$lastcourse)); $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}"); $DB->delete_records('course_categories', array('id'=>$lastcategory)); $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0"); $DB->delete_records('user', array('id'=>$lastuser)); $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id)); $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid)); context_helper::cleanup_instances(); $count = 1; //system $count += $DB->count_records('user', array('deleted'=>0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEquals($DB->count_records('context'), $count); // ======= context cache size restrictions ============================== $testusers= array(); for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) { $user = $generator->create_user(); $testusers[$i] = $user->id; } context_helper::create_instances(null, true); context_helper::reset_caches(); for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) { context_user::instance($testusers[$i]); if ($i == CONTEXT_CACHE_MAX_SIZE - 1) { $this->assertEquals(context_inspection::test_context_cache_size(), CONTEXT_CACHE_MAX_SIZE); } else if ($i == CONTEXT_CACHE_MAX_SIZE) { // once the limit is reached roughly 1/3 of records should be removed from cache $this->assertEquals(context_inspection::test_context_cache_size(), (int)(CONTEXT_CACHE_MAX_SIZE * (2/3) +102)); } } // We keep the first 100 cached $prevsize = context_inspection::test_context_cache_size(); for ($i=0; $i<100; $i++) { context_user::instance($testusers[$i]); $this->assertEquals(context_inspection::test_context_cache_size(), $prevsize); } context_user::instance($testusers[102]); $this->assertEquals(context_inspection::test_context_cache_size(), $prevsize+1); unset($testusers); // ================================================================= // ======= basic test of legacy functions ========================== // ================================================================= // note: watch out, the fake site might be pretty borked already $this->assertSame(get_system_context(), context_system::instance()); foreach ($DB->get_records('context') as $contextid=>$record) { $context = context::instance_by_id($contextid); $this->assertSame(get_context_instance_by_id($contextid), $context); $this->assertSame(get_context_instance($record->contextlevel, $record->instanceid), $context); $this->assertSame(get_parent_contexts($context), $context->get_parent_context_ids()); if ($context->id == SYSCONTEXTID) { $this->assertSame(get_parent_contextid($context), false); } else { $this->assertSame(get_parent_contextid($context), $context->get_parent_context()->id); } } $CFG->debug = 0; $children = get_child_contexts($systemcontext); $CFG->debug = DEBUG_DEVELOPER; $this->assertEquals(count($children), $DB->count_records('context')-1); unset($children); $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); create_contexts(); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK))); $DB->set_field('context', 'depth', 0, array('contextlevel'=>CONTEXT_BLOCK)); build_context_path(); $this->assertFalse($DB->record_exists('context', array('depth'=>0))); $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}"); $DB->delete_records('course', array('id'=>$lastcourse)); $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}"); $DB->delete_records('course_categories', array('id'=>$lastcategory)); $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0"); $DB->delete_records('user', array('id'=>$lastuser)); $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id)); $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid)); cleanup_contexts(); $count = 1; //system $count += $DB->count_records('user', array('deleted'=>0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEquals($DB->count_records('context'), $count); context_helper::reset_caches(); preload_course_contexts($SITE->id); $this->assertEquals(context_inspection::test_context_cache_size(), 1); context_helper::reset_caches(); list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx'); $sql = "SELECT c.id $select FROM {course_categories} c $join"; $records = $DB->get_records_sql($sql); foreach ($records as $record) { context_instance_preload($record); $record = (array)$record; $this->assertEquals(1, count($record)); // only id left } $this->assertEquals(count($records), context_inspection::test_context_cache_size()); accesslib_clear_all_caches(true); $DB->delete_records('cache_flags', array()); mark_context_dirty($systemcontext->path); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$systemcontext->path])); accesslib_clear_all_caches(false); $DB->delete_records('cache_flags', array()); $course = $DB->get_record('course', array('id'=>$testcourses[2])); $context = get_context_instance(CONTEXT_COURSE, $course->id); $oldpath = $context->path; $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}"); $categorycontext = context_coursecat::instance($miscid); $course->category = $miscid; $DB->update_record('course', $course); context_moved($context, $categorycontext); $context = get_context_instance(CONTEXT_COURSE, $course->id); $this->assertEquals($context->get_parent_context(), $categorycontext); $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2]))); delete_context(CONTEXT_COURSE, $testcourses[2]); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2]))); $name = get_contextlevel_name(CONTEXT_COURSE); $this->assertFalse(empty($name)); $context = get_context_instance(CONTEXT_COURSE, $testcourses[2]); $name = print_context_name($context); $this->assertFalse(empty($name)); $url = get_context_url($coursecontext); $this->assertFalse($url instanceof modole_url); $page = $DB->get_record('page', array('id'=>$testpages[7])); $context = get_context_instance(CONTEXT_MODULE, $page->id); $coursecontext = get_course_context($context); $this->assertEquals($coursecontext->contextlevel, CONTEXT_COURSE); $this->assertEquals(get_courseid_from_context($context), $page->course); $caps = fetch_context_capabilities($systemcontext); $this->assertTrue(is_array($caps)); unset($caps); }