/** * Associates a cluster with a track. */ public static function associate($cluster, $track, $autounenrol = true, $autoenrol = true) { global $DB; // make sure we don't double-associate if ($DB->record_exists(self::TABLE, array('clusterid' => $cluster, 'trackid' => $track))) { return; } // ELIS-7582 @set_time_limit(0); $record = new clustertrack(); $record->clusterid = $cluster; $record->trackid = $track; $record->autoenrol = $autoenrol; $record->autounenrol = $autounenrol; $record->save(); // Enrol all users in the cluster into track. $sql = 'SELECT uc.* FROM {' . clusterassignment::TABLE . '} as uc JOIN {' . user::TABLE . '} as u ON uc.userid = u.id WHERE uc.clusterid = ? ORDER BY u.lastname'; $params = array($cluster); $users = $DB->get_recordset_sql($sql, $params); if (!empty($autoenrol)) { foreach ($users as $user) { usertrack::enrol($user->userid, $track); } } unset($users); events_trigger('pm_userset_track_associated', $record); }
/** * Determines whether the current user is allowed to enrol users into the provided track * * @param int $trackid The id of the track we are checking permissions on * * @return boolean Whether the user is allowed to enrol users into the curriculum * */ static function can_enrol_into_track($trackid) { global $USER; //check the standard capability if (trackpage::_has_capability('block/curr_admin:track:enrol', $trackid)) { return true; } //get the context for the "indirect" capability $context = cm_context_set::for_user_with_capability('cluster', 'block/curr_admin:track:enrol_cluster_user', $USER->id); //get the clusters and check the context against them $clusters = clustertrack::get_clusters($trackid); if (!empty($clusters)) { foreach ($clusters as $cluster) { if ($context->context_allowed($cluster->clusterid, 'cluster')) { return true; } } } return false; }
/** * Returns an array of cluster ids that are associated to the supplied class through tracks and * the current user has access to enrol users into * * @param int $clsid The class whose association ids we care about * @return int array The array of accessible cluster ids */ public static function get_allowed_clusters($clsid) { global $USER; $context = cm_context_set::for_user_with_capability('cluster', 'block/curr_admin:class:enrol_cluster_user', $USER->id); $allowed_clusters = array(); if (cmclasspage::_has_capability('block/curr_admin:class:enrol_cluster_user', $clsid)) { global $CURMAN; require_once CURMAN_DIRLOCATION . '/lib/usercluster.class.php'; $cmuserid = cm_get_crlmuserid($USER->id); $userclusters = $CURMAN->db->get_records(CLSTUSERTABLE, 'userid', $cmuserid); foreach ($userclusters as $usercluster) { $allowed_clusters[] = $usercluster->clusterid; } } //we first need to go through tracks to get to clusters $track_listing = new trackassignmentclass(array('classid' => $clsid)); $tracks = $track_listing->get_assigned_tracks(); //iterate over the track ides, which are the keys of the array if (!empty($tracks)) { foreach (array_keys($tracks) as $track) { //get the clusters and check the context against them $clusters = clustertrack::get_clusters($track); $allowed_track_clusters = $context->get_allowed_instances($clusters, 'cluster', 'clusterid'); //append all clusters that are allowed by the available clusters contexts foreach ($allowed_track_clusters as $allowed_track_cluster) { $allowed_clusters[] = $allowed_track_cluster; } } } return $allowed_clusters; }
/** * Returns an array of cluster ids that are associated to the supplied class through tracks and * the current user has access to enrol users into * * @param int $clsid The class whose association ids we care about * @return int array The array of accessible cluster ids */ public static function get_allowed_clusters($clsid) { global $USER; $context = pm_context_set::for_user_with_capability('cluster', 'local/elisprogram:assign_userset_user_class_instructor', $USER->id); $allowed_clusters = array(); // TODO: Ugly, this needs to be overhauled $cpage = new pmclasspage(); if ($cpage->_has_capability('local/elisprogram:assign_userset_user_class_instructor', $clsid)) { require_once elispm::lib('data/clusterassignment.class.php'); $cmuserid = pm_get_crlmuserid($USER->id); $userclusters = clusterassignment::find(new field_filter('userid', $cmuserid)); foreach ($userclusters as $usercluster) { $allowed_clusters[] = $usercluster->clusterid; } } //we first need to go through tracks to get to clusters $track_listing = new trackassignment(array('classid' => $clsid)); $tracks = $track_listing->get_assigned_tracks(); //iterate over the track ides, which are the keys of the array if (!empty($tracks)) { foreach (array_keys($tracks) as $track) { //get the clusters and check the context against them $clusters = clustertrack::get_clusters($track); $allowed_track_clusters = $context->get_allowed_instances($clusters, 'cluster', 'clusterid'); //append all clusters that are allowed by the available clusters contexts foreach ($allowed_track_clusters as $allowed_track_cluster) { $allowed_clusters[] = $allowed_track_cluster; } } } return $allowed_clusters; }
/** * Associates a cluster with a track. */ static function associate($cluster, $track, $autounenrol = true, $autoenrol = true) { global $CURMAN; $db = $CURMAN->db; // make sure we don't double-associate if ($db->record_exists(CLSTTRKTABLE, 'clusterid', $cluster, 'trackid', $track)) { return; } $record = new clustertrack(); $record->clusterid = $cluster; $record->trackid = $track; $record->autoenrol = $autoenrol; $record->autounenrol = $autounenrol; $record->data_insert_record(); // Enrol all users in the cluster into track. $sql = 'SELECT uc.* FROM ' . $CURMAN->db->prefix_table(CLSTASSTABLE) . ' as uc JOIN ' . $CURMAN->db->prefix_table(USRTABLE) . ' as u ON uc.userid = u.id WHERE uc.clusterid = ' . $cluster . ' AND uc.autoenrol = 1 ORDER BY u.lastname'; $users = $db->get_records_sql($sql); // $users = $db->get_records(CLSTUSERTABLE, 'clusterid', $cluster); if ($users && !empty($autoenrol)) { foreach ($users as $user) { usertrack::enrol($user->userid, $track); } } events_trigger('crlm_cluster_track_associated', $record); }
/** * Dynamically loads child menu items for a track entity * * @param int $id The entity id * @param int $parent_cluster_id The last cluster passed going down the elisadmin tree, or 0 if none * @param int $parent_curriculum_id The last curriculum passed going down the elisadmin tree, or 0 if none * @param int $num_block_icons Max number of entries to display * @param string $parent_path Path of parent curriculum elements in the tree * @return menuitem array The appropriate child items */ function block_elisadmin_load_menu_children_track($id, $parent_cluster_id, $parent_curriculum_id, $num_block_icons, $parent_path = '') { global $CFG; //page dependencies require_once elispm::file('pmclasspage.class.php'); $result_items = array(); /***************************************** * Track - Class Associations *****************************************/ $class_css_class = block_elisadmin_get_item_css_class('class_instance'); //permissions filter $class_filter = array('contexts' => pmclasspage::get_contexts('local/elisprogram:class_view')); $listing = track_assignment_get_listing($id, 'cls.idnumber', 'ASC', 0, $num_block_icons, '', '', $class_filter); foreach ($listing as $item) { $item->id = $item->classid; $params = array('id' => $item->id, 'action' => 'view'); $result_items[] = block_elisadmin_get_menu_item('pmclass', $item, 'root', $class_css_class, $parent_cluster_id, $parent_curriculum_id, $params, false, $parent_path); } unset($listing); //summary item $num_records = track_assignment_count_records($id, '', '', $class_filter); if ($num_block_icons < $num_records) { $params = array('id' => $id); $result_items[] = block_elisadmin_get_menu_summary_item('trackassignment', $class_css_class, $num_records - $num_block_icons, $params, '', $parent_path); } /***************************************** * Track - Cluster Associations *****************************************/ $cluster_css_class = block_elisadmin_get_item_css_class('cluster_instance'); //permissions filter $cluster_filter = array('contexts' => usersetpage::get_contexts('local/elisprogram:userset_view')); $clusters = clustertrack::get_clusters($id, $parent_cluster_id, 'name', 'ASC', 0, $num_block_icons, $cluster_filter); //$clusters = clustertrack::get_clusters($id, 0, 'priority, name', 'ASC', $num_block_icons, $parent_cluster_id); if (!empty($clusters)) { foreach ($clusters as $cluster) { $cluster->id = $cluster->clusterid; $params = array('id' => $cluster->id, 'action' => 'view'); $result_items[] = block_elisadmin_get_menu_item('cluster', $cluster, 'root', $cluster_css_class, $cluster->id, $parent_curriculum_id, $params, false, $parent_path); } } //summary item $num_records = clustertrack::count_clusters($id, $parent_cluster_id, $cluster_filter); if ($num_block_icons < $num_records) { $params = array('id' => $id); //add extra param if appropriate if (!empty($parent_cluster_id)) { $params['parent_clusterid'] = $parent_cluster_id; } $result_items[] = block_elisadmin_get_menu_summary_item('trackcluster', $cluster_css_class, $num_records - $num_block_icons, $params, 'clustertrackpage.class.php', $parent_path); } return $result_items; }
/** * Clone a track * @param array $options options for cloning. Valid options are: * - 'targetcurriculum': the curriculum id to associate the clones with * (default: same as original track) * - 'classmap': a mapping of class IDs to use from the original track to * the cloned track. If a class from the original track is not mapped, a * new class will be created * - 'moodlecourse': whether or not to clone Moodle courses (if they were * autocreated). Values can be (default: "copyalways"): * - "copyalways": always copy course * - "copyautocreated": only copy autocreated courses * - "autocreatenew": autocreate new courses from course template * - "link": link to existing course * @return array array of array of object IDs created. Key in outer array * is type of object (plural). Key in inner array is original object ID, * value is new object ID. Outer array also has an entry called 'errors', * which is an array of any errors encountered when duplicating the * object. */ function duplicate(array $options = array()) { $objs = array('errors' => array()); if (isset($options['targetcluster'])) { $userset = $options['targetcluster']; if (!is_object($userset) || !is_a($userset, 'userset')) { $options['targetcluster'] = $userset = new userset($userset); } } // Due to lazy loading, we need to pre-load this object $this->load(); // clone main track object $clone = new track($this); unset($clone->id); if (isset($options['targetcurriculum'])) { $clone->curid = $options['targetcurriculum']; } $idnumber = $clone->idnumber; $name = $clone->name; if (isset($userset)) { $to_append = ' - ' . $userset->name; // if cluster specified, append cluster's name to course $idnumber = append_once($idnumber, $to_append, array('maxlength' => 95)); $name = append_once($name, $to_append, array('maxlength' => 250)); } //get a unique idnumber $clone->idnumber = generate_unique_identifier(track::TABLE, 'idnumber', $idnumber, array('idnumber' => $idnumber)); if ($clone->idnumber != $idnumber) { //get the suffix appended and add it to the name $parts = explode('.', $clone->idnumber); $suffix = end($parts); $clone->name = $name . '.' . $suffix; } else { $clone->name = $name; } $clone->autocreate = false; // avoid warnings $clone->save(); $objs['tracks'] = array($this->id => $clone->id); // associate with target cluster (if any) if (isset($userset)) { clustertrack::associate($userset->id, $clone->id); } // copy classes $clstrks = track_assignment_get_listing($this->id); if ($clstrks->valid() === true) { $objs['classes'] = array(); if (!isset($options['classmap'])) { $options['classmap'] = array(); } foreach ($clstrks as $clstrkdata) { $newclstrk = new trackassignment($clstrkdata); $newclstrk->trackid = $clone->id; unset($newclstrk->id); if (isset($options['classmap'][$clstrkdata->clsid])) { // use existing duplicate class $class = new pmclass($options['classmap'][$clstrkdata->clsid]); } else { // no existing duplicate -> duplicate class $class = new pmclass($clstrkdata->clsid); $rv = $class->duplicate($options); if (isset($rv['errors']) && !empty($rv['errors'])) { $objs['errors'] = array_merge($objs['errors'], $rv['errors']); } if (isset($rv['classes'])) { $objs['classes'] = $objs['classes'] + $rv['classes']; } } $newclstrk->classid = $class->id; $newclstrk->courseid = $class->courseid; $newclstrk->save(); } } unset($clstrks); return $objs; }
function action_default() { $id = $this->required_param('id', PARAM_INT); $parent_clusterid = $this->optional_param('parent_clusterid', 0, PARAM_INT); $sort = $this->optional_param('sort', 'name', PARAM_CLEAN); $dir = $this->optional_param('dir', 'ASC', PARAM_CLEAN); $columns = array('name' => get_string('cluster_name', 'block_curr_admin'), 'display' => get_string('description', 'block_curr_admin'), 'autoenrol' => get_string('auto_enrol', 'block_curr_admin'), 'buttons' => ''); $items = clustertrack::get_clusters($id, $parent_clusterid, $sort, $dir); $formatters = $this->create_link_formatters(array('name'), 'clusterpage', 'clusterid'); $this->print_list_view($items, $columns, $formatters, 'clusters'); // find the tracks that the user can associate with this cluster $contexts = clusterpage::get_contexts('block/curr_admin:associate'); $clusters = cluster_get_listing('name', 'ASC', 0, 0, '', '', array('contexts' => $contexts)); if (empty($clusters)) { $num_clusters = cluster_count_records(); if (!empty($num_clusters)) { // some clusters exist, but don't have associate capability on // any of them echo '<div align="center"><br />'; print_string('no_associate_caps_cluster', 'block_curr_admin'); echo '</div>'; } else { // no clusters at all echo '<div align="center"><br />'; print_string('all_items_assigned', 'block_curr_admin'); echo '</div>'; } } else { $this->print_dropdown($clusters, $items, 'trackid', 'clusterid'); } }
$sql = 'FROM ' . $CURMAN->db->prefix_table(USRTABLE) . ' usr ' . 'LEFT OUTER JOIN ' . $CURMAN->db->prefix_table(USRTRKTABLE) . ' ut ON ut.userid = usr.id AND ut.trackid = ' . $trackid . ' ' . 'WHERE ut.userid IS NULL '; if (empty($CURMAN->config->legacy_show_inactive_users)) { $sql .= 'AND usr.inactive = 0 '; } if ($alpha) { $sql .= 'AND ' . $FULLNAME . ' ' . $LIKE . ' \'' . $alpha . '%\' '; } if ($namesearch) { $sql .= 'AND ' . $FULLNAME . ' ' . $LIKE . ' \'%' . $namesearch . '%\' '; } if (!trackpage::_has_capability('block/curr_admin:track:enrol', $trackid)) { //perform SQL filtering for the more "conditional" capability //get the context for the "indirect" capability $context = cm_context_set::for_user_with_capability('cluster', 'block/curr_admin:track:enrol_cluster_user', $USER->id); //get the clusters and check the context against them $clusters = clustertrack::get_clusters($trackid); $allowed_clusters = $context->get_allowed_instances($clusters, 'cluster', 'clusterid'); if (empty($allowed_clusters)) { $sql .= 'AND 0=1'; } else { $cluster_filter = implode(',', $allowed_clusters); $sql .= "AND usr.id IN (\n SELECT userid FROM " . $CURMAN->db->prefix_table(CLSTUSERTABLE) . "\n WHERE clusterid IN ({$cluster_filter}))"; } } // get the total number of matching users $count = $CURMAN->db->count_records_sql('SELECT COUNT(usr.id) ' . $sql); if ($sort) { $sql .= 'ORDER BY ' . $sort . ' ' . $dir . ' '; } if ($count < $page * $perpage) { $page = 0;
/** * Validate that enrolling a user into a user set via IP auto-enrolls them in * an associated track, and any associated programs or class instances */ public function test_userset_enrolment_creates_track_enrolment() { global $CFG, $DB; require_once $CFG->dirroot . '/local/elisprogram/lib/setup.php'; require_once elispm::lib('data/clustertrack.class.php'); require_once elispm::lib('data/course.class.php'); require_once elispm::lib('data/curriculum.class.php'); require_once elispm::lib('data/curriculumcourse.class.php'); require_once elispm::lib('data/curriculumstudent.class.php'); require_once elispm::lib('data/pmclass.class.php'); require_once elispm::lib('data/student.class.php'); require_once elispm::lib('data/track.class.php'); require_once elispm::lib('data/user.class.php'); require_once elispm::lib('data/userset.class.php'); require_once elispm::lib('data/usertrack.class.php'); // Make sure no emails are sent. set_config('noemailever', true); // Set up data. // Test user. $user = new user(array('idnumber' => 'testuseridnumber', 'username' => 'testuserusername', 'firstname' => 'testuserfirstname', 'firstname' => 'testuserfirstname', 'lastname' => 'testuserlastname', 'email' => '*****@*****.**', 'country' => 'CA')); $user->save(); // Test user set. $userset = new userset(array('name' => 'testusersetname')); $userset->save(); // Test program and track. $program = new curriculum(array('idnumber' => 'testprogramidnumber')); $program->save(); $track = new track(array('curid' => $program->id, 'idnumber' => 'testtrackidnumber')); $track->save(); // Associate the userset to the track. $clustertrack = new clustertrack(array('clusterid' => $userset->id, 'trackid' => $track->id, 'autoenrol' => 1)); $clustertrack->save(); // Test course and class. $course = new course(array('name' => 'testcoursename', 'idnumber' => 'testcourseidnumber', 'syllabus' => '')); $course->save(); $class = new pmclass(array('courseid' => $course->id, 'idnumber' => 'testclass1idnumber')); $class->save(); // Associate course to the program. $curriculumcourse = new curriculumcourse(array('curriculumid' => $program->id, 'courseid' => $course->id)); $curriculumcourse->save(); // Associate track to the test class. $trackassignment = new trackassignment(array('trackid' => $track->id, 'classid' => $class->id, 'autoenrol' => 1)); $trackassignment->save(); // Run the assignment create action. $record = new stdClass(); $record->context = 'userset_testusersetname'; $record->user_username = '******'; $importplugin = rlip_dataplugin_factory::factory('dhimport_version1elis'); $importplugin->fslogger = new silent_fslogger(null); $importplugin->cluster_enrolment_create($record, 'bogus', 'testusersetname'); // Validation. // Userset assignment should trigger track assignment. $this->assertTrue($DB->record_exists(usertrack::TABLE, array('userid' => $user->id, 'trackid' => $track->id))); // Track assignment should trigger program assignment. $this->assertTrue($DB->record_exists(curriculumstudent::TABLE, array('userid' => $user->id, 'curriculumid' => $program->id))); // Track assignment should create a class enrolment. $this->assertTrue($DB->record_exists(student::TABLE, array('userid' => $user->id, 'classid' => $class->id))); }
/** * @dataProvider sortautoenroldescprovider */ public function testsortautoenroldesc($data) { $this->load_csv_data(); $dataset = clustertrack::get_tracks(1, 'autoenrol', 'DESC'); $this->assertEquals(array_values($data), array_values($dataset)); }
/** * Perform the necessary actions required to "delete" a cluster from the system. * * @param none * @return bool True on success, False otherwise. */ function delete() { require_once elis::lib('data/data_filter.class.php'); if ($this->deletesimple) { //core delete method, not including recursion (entered once for each //individual userset being delete) //clean make the delete cascade into association records $filter = new field_filter('clusterid', $this->id); clustercurriculum::delete_records($filter, $this->_db); clustertrack::delete_records($filter, $this->_db); clusterassignment::delete_records($filter, $this->_db); //cluster plugin cleanup $plugins = get_plugin_list(self::ENROL_PLUGIN_TYPE); foreach ($plugins as $plugin => $plugindir) { require_once elis::plugin_file(self::ENROL_PLUGIN_TYPE . '_' . $plugin, 'lib.php'); call_user_func('cluster_' . $plugin . '_delete_for_cluster', $this->id); } //delete the userset record parent::delete(); //delete this cluster's context //get a new context instance, $contextclass = \local_eliscore\context\helper::get_class_for_level(CONTEXT_ELIS_USERSET); $userset_context = $contextclass::instance($this->id); $userset_context->delete(); events_trigger('cluster_deleted', $this->id); return; } $result = true; $children = array(); $delete_ids = array(); $promote_ids = array(); /// Figure out all the sub-clusters $cluster_context_instance = \local_elisprogram\context\userset::instance($this->id); $instance_id = $cluster_context_instance->id; $instance_path = $cluster_context_instance->path; $children = userset::find(new join_filter('id', 'context', 'instanceid', new AND_filter(array(new field_filter('path', "{$instance_path}/%", field_filter::LIKE), new field_filter('contextlevel', CONTEXT_ELIS_USERSET)))), array('depth' => 'ASC'), 0, 0, $this->_db); $children = $children->to_array(); if ($this->deletesubs) { $todelete = $children; $todelete[] = $this; // The specified cluster always gets deleted } else { $todelete = array($this); } foreach ($todelete as $userset) { //delete without recursion $userset->deletesimple = true; $userset->delete(); } if (!$this->deletesubs && !empty($children)) { foreach ($children as $child) { $lower_depth = $child->depth - 1; if (userset::exists(new field_filter('id', $child->parent))) { /// A parent found so lets lower the depth $child->depth = 0; } else { /// Parent not found so this cluster will be top-level $child->parent = 0; $child->depth = 1; } $child->save(); $sql = "UPDATE {context}\n SET depth=0, path=NULL\n WHERE contextlevel=? AND instanceid=?"; $this->_db->execute($sql, array(CONTEXT_ELIS_USERSET, $child->id)); } \local_eliscore\context\helper::build_all_paths(false, array(CONTEXT_ELIS_USERSET)); // Re-build the context table for all sub-clusters } return $result; }
/** * Determines whether the current user is allowed to enrol users into the provided track * * @param int $trackid The id of the track we are checking permissions on * * @return boolean Whether the user is allowed to enrol users into the curriculum * */ public static function can_enrol_into_track($trackid) { global $USER; //check the standard capability // TODO: Ugly, this needs to be overhauled $tpage = new trackpage(); if ($tpage->_has_capability('local/elisprogram:track_enrol', $trackid)) { return true; } //get the context for the "indirect" capability $context = pm_context_set::for_user_with_capability('cluster', 'local/elisprogram:track_enrol_userset_user', $USER->id); //get the clusters and check the context against them $clusters = clustertrack::get_clusters($trackid); if (!empty($clusters)) { foreach ($clusters as $cluster) { if ($context->context_allowed($cluster->clusterid, 'cluster')) { return true; } } } return false; }
/** * Determines whether the current user is allowed to enrol users into the provided class * * @param int $classid The id of the class we are checking permissions on * * @return boolean Whether the user is allowed to enrol users into the class * */ static function can_enrol_into_class($classid) { global $USER; //check the standard capability if (cmclasspage::_has_capability('block/curr_admin:class:enrol', $classid) || cmclasspage::_has_capability('block/curr_admin:class:enrol_cluster_user', $classid)) { return true; } //get the context for the "indirect" capability $context = cm_context_set::for_user_with_capability('cluster', 'block/curr_admin:class:enrol_cluster_user', $USER->id); //we first need to go through tracks to get to clusters $track_listing = new trackassignmentclass(array('classid' => $classid)); $tracks = $track_listing->get_assigned_tracks(); //iterate over the track ides, which are the keys of the array if (!empty($tracks)) { foreach (array_keys($tracks) as $track) { //get the clusters and check the context against them $clusters = clustertrack::get_clusters($track); if (!empty($clusters)) { foreach ($clusters as $cluster) { if ($context->context_allowed($cluster->clusterid, 'cluster')) { return true; } } } } } return false; }
static function cluster_assigned_handler($eventdata) { global $CURMAN, $CFG; // assign user to the curricula associated with the cluster /** * @todo we may need to change this if associating a user with a * curriculum does anything more complicated */ require_once CURMAN_DIRLOCATION . '/lib/user.class.php'; require_once CURMAN_DIRLOCATION . '/lib/clustercurriculum.class.php'; require_once CURMAN_DIRLOCATION . '/lib/curriculumstudent.class.php'; require_once CURMAN_DIRLOCATION . '/lib/usertrack.class.php'; $db = $CURMAN->db; $timenow = time(); $sql = 'INSERT INTO ' . $db->prefix_table(CURASSTABLE) . ' ' . '(userid, curriculumid, timecreated, timemodified) ' . 'SELECT DISTINCT u.id, clucur.curriculumid, ' . $timenow . ', ' . $timenow . ' ' . 'FROM ' . $db->prefix_table(CLSTUSERTABLE) . ' clu ' . 'INNER JOIN ' . $db->prefix_table(USRTABLE) . ' u ON u.id = clu.userid ' . 'INNER JOIN ' . $db->prefix_table(CLSTCURTABLE) . ' clucur ON clucur.clusterid = clu.clusterid ' . 'LEFT OUTER JOIN ' . $db->prefix_table(CURASSTABLE) . ' ca ON ca.userid = u.id AND ca.curriculumid = clucur.curriculumid ' . 'WHERE clu.clusterid = \'' . $eventdata->clusterid . '\' AND u.id = \'' . $eventdata->userid . '\' AND ca.curriculumid IS NULL ' . 'AND clucur.autoenrol = 1'; $db->execute_sql($sql, false); // enrol user in associated tracks if autoenrol flag is set if ($eventdata->autoenrol) { $tracks = clustertrack::get_tracks($eventdata->clusterid); if ($tracks) { foreach ($tracks as $track) { //make sure the cluster-track association is set up for autoenrol if (record_exists(CLSTTRKTABLE, 'clusterid', $eventdata->clusterid, 'trackid', $track->trackid, 'autoenrol', 1)) { usertrack::enrol($eventdata->userid, $track->trackid); } } } } return true; }
/** * Determines whether the current user is allowed to enrol users into the provided class * * @param int $classid The id of the class we are checking permissions on * * @return boolean Whether the user is allowed to enrol users into the class * */ static function can_enrol_into_class($classid) { global $USER; //check the standard capability // TODO: Ugly, this needs to be overhauled $cpage = new pmclasspage(); if ($cpage->_has_capability('local/elisprogram:class_enrol', $classid) || $cpage->_has_capability('local/elisprogram:class_enrol_userset_user', $classid)) { return true; } //get the context for the "indirect" capability $context = pm_context_set::for_user_with_capability('cluster', 'local/elisprogram:class_enrol_userset_user', $USER->id); //we first need to go through tracks to get to clusters $track_listing = new trackassignment(array('classid' => $classid)); $tracks = $track_listing->get_assigned_tracks(); //iterate over the track ides, which are the keys of the array if (!empty($tracks)) { foreach (array_keys($tracks) as $track) { //get the clusters and check the context against them $clusters = clustertrack::get_clusters($track); if (!empty($clusters)) { foreach ($clusters as $cluster) { if ($context->context_allowed($cluster->clusterid, 'cluster')) { return true; } } } } } return false; }
/** * Test validation of duplicates * @expectedException data_object_validation_exception */ public function test_clustertrack_validationpreventsduplicates() { $this->load_csv_data(); $clustertrack = new clustertrack(array('clusterid' => 1, 'trackid' => 1)); $clustertrack->save(); }
/** * Unassign the tracks from the userset. * @param array $elements An array of track information to unassign from the userset. * @param bool $bulkaction Whether this is a bulk-action or not. * @return array An array to format as JSON and return to the Javascript. */ protected function _respond_to_js(array $elements, $bulkaction) { global $DB; $usersetid = required_param('id', PARAM_INT); foreach ($elements as $trackid => $label) { if ($this->can_unassign($usersetid, $trackid) === true) { $assignrec = $DB->get_record(clustertrack::TABLE, array('clusterid' => $usersetid, 'trackid' => $trackid)); $usertrack = new clustertrack($assignrec); $usertrack->delete(); } } return array('result' => 'success', 'msg' => 'Success'); }
/** * Obtain the count of users who can be assigned to the provided track * * @param int $trackid The record id of the track we are currently assigning to * @param string $namesearch A substring of users' fullnames to search by * @param string $alpha The first letter of users' fullnames to search by * * @return array The total count of appropriate users */ public static function count_available_users($trackid, $namesearch = '', $alpha = '') { global $CFG, $DB, $USER; require_once elispm::file('trackpage.class.php'); require_once elispm::lib('data/clusterassignment.class.php'); $FULLNAME = $DB->sql_concat('usr.firstname', "' '", 'usr.lastname'); $select = 'SELECT COUNT(*) '; $sql = 'FROM {' . user::TABLE . '} usr ' . 'LEFT OUTER JOIN {' . usertrack::TABLE . '} ut ON ut.userid = usr.id AND ut.trackid = :trackid ' . 'WHERE ut.userid IS NULL '; $params = array('trackid' => $trackid); if ($namesearch != '') { $NAMELIKE = $DB->sql_like($FULLNAME, ':namesearch', false); $namesearch = trim($namesearch); $sql .= 'AND ' . $NAMELIKE . ' '; $params['namesearch'] = "%{$namesearch}%"; } if ($alpha != '') { //todo: determine if this should actually be using last name? $ALPHA_LIKE = $DB->sql_like($FULLNAME, ':lastname', false); $sql .= 'AND ' . $ALPHA_LIKE . ' '; $params['lastname'] = "{$alpha}%"; } if (empty(elis::$config->local_elisprogram->legacy_show_inactive_users)) { $sql .= 'AND usr.inactive = 0 '; } // TODO: Ugly, this needs to be overhauled $tpage = new trackpage(); if (!$tpage->_has_capability('local/elisprogram:track_enrol', $trackid)) { //perform SQL filtering for the more "conditional" capability //get the context for the "indirect" capability $context = pm_context_set::for_user_with_capability('cluster', 'local/elisprogram:track_enrol_userset_user', $USER->id); //get the clusters and check the context against them $clusters = clustertrack::get_clusters($trackid); $allowed_clusters = $context->get_allowed_instances($clusters, 'cluster', 'clusterid'); if (empty($allowed_clusters)) { $sql .= 'AND 0=1 '; } else { $cluster_filter = implode(',', $allowed_clusters); $sql .= "AND usr.id IN (\n SELECT userid FROM {" . clusterassignment::TABLE . "}\n WHERE clusterid IN (:clusterfilter)) "; $params['clusterfilter'] = $cluster_filter; } } return $DB->count_records_sql($select . $sql, $params); }
/** * Clone a track * @param array $options options for cloning. Valid options are: * - 'targetcurriculum': the curriculum id to associate the clones with * (default: same as original track) * - 'classmap': a mapping of class IDs to use from the original track to * the cloned track. If a class from the original track is not mapped, a * new class will be created * - 'moodlecourse': whether or not to clone Moodle courses (if they were * autocreated). Values can be (default: "copyalways"): * - "copyalways": always copy course * - "copyautocreated": only copy autocreated courses * - "autocreatenew": autocreate new courses from course template * - "link": link to existing course * @return array array of array of object IDs created. Key in outer array * is type of object (plural). Key in inner array is original object ID, * value is new object ID. Outer array also has an entry called 'errors', * which is an array of any errors encountered when duplicating the * object. */ function duplicate($options = array()) { global $CURMAN; $objs = array('errors' => array()); if (isset($options['targetcluster'])) { $cluster = $options['targetcluster']; if (!is_object($cluster) || !is_a($cluster, 'cluster')) { $options['targetcluster'] = $cluster = new cluster($cluster); } } // clone main track object $clone = new track($this); unset($clone->id); if (isset($options['targetcurriculum'])) { $clone->curid = $options['targetcurriculum']; } if (isset($cluster)) { // if cluster specified, append cluster's name to track $clone->idnumber = $clone->idnumber . ' - ' . $cluster->name; $clone->name = $clone->name . ' - ' . $cluster->name; } $clone = new track(addslashes_recursive($clone)); $clone->autocreate = false; // avoid warnings if (!$clone->add()) { $objs['errors'][] = get_string('failclustcpytrk', 'block_curr_admin', $this); return $objs; } $objs['tracks'] = array($this->id => $clone->id); // associate with target cluster (if any) if (isset($cluster)) { clustertrack::associate($cluster->id, $clone->id); } // copy classes $clstrks = track_assignment_get_listing($this->id); if (!empty($clstrks)) { $objs['classes'] = array(); if (!isset($options['classmap'])) { $options['classmap'] = array(); } foreach ($clstrks as $clstrkdata) { $newclstrk = new trackassignmentclass($clstrkdata); $newclstrk->trackid = $clone->id; unset($newclstrk->id); if (isset($options['classmap'][$clstrkdata->clsid])) { // use existing duplicate class $class = new cmclass($options['classmap'][$clstrkdata->clsid]); } else { // no existing duplicate -> duplicate class $class = new cmclass($clstrkdata->clsid); $rv = $class->duplicate($options); if (isset($rv['errors']) && !empty($rv['errors'])) { $objs['errors'] = array_merge($objs['errors'], $rv['errors']); } if (isset($rv['classes'])) { $objs['classes'] = $objs['classes'] + $rv['classes']; } } $newclstrk->classid = $class->id; $newclstrk->courseid = $class->courseid; $newclstrk->add(); } } return $objs; }
/** * Validate that the listing respects the local/elisprogram:track_enrol_userset_user * capability as long as the appropriate userset and track are associated to * one another and the target user is in the userset */ public function test_availableusersrespectsindirectusersetpermissions() { global $DB, $USER; $this->load_csv_data(); set_config('siteguest', ''); set_config('siteadmins', ''); accesslib_clear_all_caches_for_unit_testing(); // Create a test user to be in the userset. $usersetmember = new user(array('idnumber' => 'usersetmember', 'username' => 'usersetmember', 'firstname' => 'usersetmember', 'lastname' => 'usersetmember', 'email' => '*****@*****.**', 'country' => 'CA')); $usersetmember->save(); // Our test userset. $userset = new userset(array('name' => 'userset')); $userset->save(); // Assign the test user to the test userset. $clusterassignment = new clusterassignment(array('userid' => $usersetmember->id, 'clusterid' => $userset->id)); $clusterassignment->save(); // Assign the userset to our track. $clustertrack = new clustertrack(array('clusterid' => $userset->id, 'trackid' => 1)); $clustertrack->save(); // Set up a db record for the active user for permissions reasons. // (i.e. so they are not treated as an admin). $activeuser = new user(array('idnumber' => 'activeuser', 'username' => 'activeuser', 'firstname' => 'activeuser', 'lastname' => 'activeuser', 'email' => '*****@*****.**', 'country' => 'CA')); $activeuser->save(); // Set up our test role. $roleid = create_role('testrole', 'testrole', 'testrole'); $syscontext = context_system::instance(); assign_capability('local/elisprogram:track_enrol_userset_user', CAP_ALLOW, $roleid, $syscontext->id); // Perform the role necessary assignment. $moodleuser = $DB->get_record('user', array('username' => 'activeuser')); // Make sure all the contexts are created, so that we can find the children. $contextclass = \local_eliscore\context\helper::get_class_for_level(CONTEXT_ELIS_USERSET); $instance = $contextclass::instance($userset->id); role_assign($roleid, $moodleuser->id, $instance->id); // Assume the role of the user with the role assignment. $USER = $moodleuser; $usersrecset = usertrack::get_available_users(1); $users = array(); foreach ($usersrecset as $key => $user) { $users[$key] = $user; } unset($usersrecset); $this->assertEquals(1, count($users)); // Validate user. $this->assertArrayHasKey($usersetmember->id, $users); $user = $users[$usersetmember->id]; $this->assertEquals($usersetmember->username, 'usersetmember'); // Validate count. $count = usertrack::count_available_users(1); $this->assertEquals(1, $count); }
/** * Test available table obeys track_enrol_userset_users permission. * * Test available table shows only users that are in clusters where: * - the assigner is also in the cluster * - the assigner has the local/elisprogram:track_enrol_userset_user permission * - the current track is associated with the cluster. * * @dataProvider dataprovider_available_permissions_track_enrol_userset_user * @param array $usersetidsforperm An array of userset IDs to assign the local/elisprogram:track_enrol_userset_user on. * @param array $clusterassignments An array of arrays of parameters to construct clusterassignments with. * @param array $clustertracks An array of arrays of parameters to construct clustertracks with. * @param int $tabletrackid The id of the track to manage associations for. * @param array $expectedresults The expected page of results. * @param int $expectedtotal The expected number of total results. */ public function test_available_permissions_track_enrol_userset_user($usersetidsforperm, $clusterassignments, $clustertracks, $tabletrackid, $expectedresults, $expectedtotal) { global $USER, $DB, $CFG; $userbackup = $USER; // Import usersets. $dataset = $this->createCsvDataSet(array(userset::TABLE => elispm::file('tests/fixtures/deepsight_userset.csv'))); $this->loadDataSet($dataset); // Set up permissions. $USER = $this->setup_permissions_test(); $capability = 'local/elisprogram:track_enrol_userset_user'; foreach ($usersetidsforperm as $usersetid) { $this->give_permission_for_context($USER->id, $capability, \local_elisprogram\context\userset::instance($usersetid)); } // Create clusterassignments. foreach ($clusterassignments as $clusterassignment) { $clusterassignment = new clusterassignment($clusterassignment); $clusterassignment->save(); } // Create clustertracks. foreach ($clustertracks as $clustertrack) { $clustertrack = new clustertrack($clustertrack); $clustertrack->save(); } // Construct test table. $table = new deepsight_datatable_trackuser_available_mock($DB, 'test', 'http://localhost', 'testuniqid'); $table->set_trackid($tabletrackid); // Perform test. $actualresults = $table->get_search_results(array(), array(), 0, 20); // Verify. $this->assert_search_results($expectedresults, $expectedtotal, $actualresults); // Restore user. $USER = $userbackup; }
/** * Test available table doesn't show assigned tracks. * @dataProvider dataprovider_available_doesnt_show_assigned_tracks * @param array $associations An array of arrays of parameters to construct clustertrack associations. * @param int $tableusersetid The ID of the userset we're going to manage. * @param array $expectedresults The expected page of results. * @param int $expectedtotal The expected number of total results. */ public function test_available_doesnt_show_assigned_tracks($associations, $tableusersetid, $expectedresults, $expectedtotal) { global $USER, $DB, $CFG; $userbackup = $USER; // Set up permissions. $USER = $this->setup_permissions_test(); $this->give_permission_for_context($USER->id, 'local/elisprogram:associate', context_system::instance()); foreach ($associations as $association) { $clustertrack = new clustertrack($association); $clustertrack->save(); } // Construct test table. $table = new deepsight_datatable_usersettrack_available_mock($DB, 'test', 'http://localhost', 'testuniqid'); $table->set_usersetid($tableusersetid); // Perform test. $actualresults = $table->get_search_results(array(), array(), 0, 20); // Verify result. $this->assert_search_results($expectedresults, $expectedtotal, $actualresults); // Restore user. $USER = $userbackup; }
/** * Determines whether the current user is allowed to create, edit, and delete associations * between a user and a track * * @param int $userid The id of the user being associated to the track * @param int $trackid The id of the track we are associating the user to * * @return boolean True if the current user has the required permissions, otherwise false */ public static function can_manage_assoc($userid, $trackid) { global $USER; //get the context for the "indirect" capability $context = cm_context_set::for_user_with_capability('cluster', 'block/curr_admin:track:enrol_cluster_user', $USER->id); $allowed_clusters = array(); if (!trackpage::can_enrol_into_track($trackid)) { //the users who satisfty this condition are a superset of those who can manage associations return false; } else { if (trackpage::_has_capability('block/curr_admin:track:enrol', $trackid)) { //current user has the direct capability return true; } } //get the clusters and check the context against them $clusters = clustertrack::get_clusters($trackid); $allowed_clusters = $context->get_allowed_instances($clusters, 'cluster', 'clusterid'); //query to get users associated to at least one enabling cluster $cluster_select = ''; if (empty($allowed_clusters)) { $cluster_select = '0=1'; } else { $cluster_select = 'clusterid IN (' . implode(',', $allowed_clusters) . ')'; } $select = "userid = {$userid} AND {$cluster_select}"; //user just needs to be in one of the possible clusters if (record_exists_select(CLSTUSERTABLE, $select)) { return true; } return false; }
/** * Validate that deleting a userset deletes all appropriate associations */ public function test_delete_elis_userset_deletes_associations() { global $CFG, $DB; // Entities. require_once $CFG->dirroot . '/local/elisprogram/lib/setup.php'; require_once elispm::lib('data/userset.class.php'); require_once elispm::lib('data/user.class.php'); require_once elispm::lib('data/curriculum.class.php'); require_once elispm::lib('data/track.class.php'); require_once elis::lib('data/customfield.class.php'); // Associations. require_once elispm::lib('data/clusterassignment.class.php'); require_once elispm::lib('data/clustercurriculum.class.php'); require_once elispm::lib('data/clustertrack.class.php'); require_once elispm::file('enrol/userset/moodleprofile/userset_profile.class.php'); // For context level access. require_once elispm::file('accesslib.php'); $origfieldcount = $DB->count_records(field::TABLE); // Set up user set. $userset = new userset(array('name' => 'testusersetname')); $userset->save(); // Set up other entities and associations. // Cluster enrolment. $user = new user(array('idnumber' => 'testuseridnumber', 'username' => 'testuserusername', 'firstname' => 'testuserfirstname', 'lastname' => 'testuserlastname', 'email' => '*****@*****.**', 'country' => 'CA')); $user->save(); $clusterassignment = new clusterassignment(array('clusterid' => $userset->id, 'userid' => $user->id)); $clusterassignment->save(); // Cluster-curriculum assignment. $curriculum = new curriculum(array('idnumber' => 'testcurriculumidnumber')); $curriculum->save(); $clustercurriculum = new clustercurriculum(array('clusterid' => $userset->id, 'curriculumid' => $curriculum->id)); $clustercurriculum->save(); // Cluster-track assignment. $track = new track(array('curid' => $curriculum->id, 'idnumber' => 'testtrackidnumber')); $track->save(); $clustertrack = new clustertrack(array('clusterid' => $userset->id, 'trackid' => $track->id)); $clustertrack->save(); // Custom field. $field = new field(array('name' => 'testfieldname', 'categoryid' => 9999)); $field->save(); $context = \local_elisprogram\context\userset::instance($userset->id); $data = new field_data_int(array('contextid' => $context->id, 'fieldid' => $field->id, 'data' => 1)); $data->save(); // Cluster profile criteria. $clusterprofile = new userset_profile(array('clusterid' => $userset->id, 'fieldid' => $field->id, 'value' => 0)); $clusterprofile->save(); // Validate setup. $this->assertEquals(1, $DB->count_records(userset::TABLE)); $this->assertEquals(1, $DB->count_records(user::TABLE)); $this->assertEquals(1, $DB->count_records(clusterassignment::TABLE)); $this->assertEquals(1, $DB->count_records(curriculum::TABLE)); $this->assertEquals(1, $DB->count_records(clustercurriculum::TABLE)); $this->assertEquals(1, $DB->count_records(track::TABLE)); $this->assertEquals(1, $DB->count_records(clustertrack::TABLE)); $this->assertEquals(1 + $origfieldcount, $DB->count_records(field::TABLE)); $this->assertEquals(1, $DB->count_records(field_data_int::TABLE)); $this->assertEquals(1, $DB->count_records(userset_profile::TABLE)); // Run the import. $data = array('action' => 'delete'); $this->run_core_userset_import($data, true); // Validation. $this->assertEquals(0, $DB->count_records(userset::TABLE)); $this->assertEquals(1, $DB->count_records(user::TABLE)); $this->assertEquals(0, $DB->count_records(clusterassignment::TABLE)); $this->assertEquals(1, $DB->count_records(curriculum::TABLE)); $this->assertEquals(0, $DB->count_records(clustercurriculum::TABLE)); $this->assertEquals(1, $DB->count_records(track::TABLE)); $this->assertEquals(0, $DB->count_records(clustertrack::TABLE)); $this->assertEquals(1 + $origfieldcount, $DB->count_records(field::TABLE)); $this->assertEquals(0, $DB->count_records(field_data_int::TABLE)); $this->assertEquals(0, $DB->count_records(userset_profile::TABLE)); }
/** * Set up data that is needed for testing */ private function set_up_required_data($assignusertouserset = true, $assigncoursetoclass = true, $assigntracktoclass = true, $initclusterprofile = false, $initusersetfielddata = true) { global $CFG, $DB; require_once $CFG->dirroot . '/local/elisprogram/lib/setup.php'; require_once $CFG->dirroot . '/course/lib.php'; require_once $CFG->dirroot . '/lib/enrollib.php'; require_once elis::lib('data/customfield.class.php'); require_once elispm::file('accesslib.php'); require_once elispm::lib('data/classmoodlecourse.class.php'); require_once elispm::lib('data/clusterassignment.class.php'); require_once elispm::lib('data/clustertrack.class.php'); require_once elispm::lib('data/course.class.php'); require_once elispm::lib('data/curriculum.class.php'); require_once elispm::lib('data/pmclass.class.php'); require_once elispm::lib('data/track.class.php'); require_once elispm::lib('data/user.class.php'); require_once elispm::lib('data/userset.class.php'); require_once elispm::lib('data/usertrack.class.php'); $fieldcategoryid = $DB->get_field(field_category::TABLE, 'id', array('name' => 'Associated Group')); $this->assertNotEquals(false, $fieldcategoryid); $fieldcategory = new field_category($fieldcategoryid); $fieldcategory->load(); // Set up the test user. $user = new user(array('idnumber' => 'testuseridnumber', 'username' => 'testuserusername', 'firstname' => 'testuserfirstname', 'lastname' => 'testuserlastname', 'email' => '*****@*****.**', 'country' => 'CA')); $user->save(); // Set up the test course description and class instance. $course = new course(array('name' => 'testcoursename', 'idnumber' => 'testcourseidnumber', 'syllabus' => '')); $course->save(); $pmclass = new pmclass(array('courseid' => $course->id, 'idnumber' => 'testclassidnumber')); $pmclass->save(); $category = new stdClass(); $category->name = 'testcategoryname'; $category->id = $DB->insert_record('course_categories', $category); // Set up the test Moodle course. set_config('enrol_plugins_enabled', 'manual'); set_config('defaultenrol', 1, 'enrol_manual'); set_config('status', ENROL_INSTANCE_ENABLED, 'enrol_manual'); $course = new stdClass(); $course->category = $category->id; $course->shortname = 'testcourseshortname'; $course->fullname = 'testcoursefullname'; $course = create_course($course); if ($assigncoursetoclass) { // Assign the Moodle course to a class instance. $classmoodlecourse = new classmoodlecourse(array('classid' => $pmclass->id, 'moodlecourseid' => $course->id)); $classmoodlecourse->save(); } // Set up the test program and track. $curriculum = new curriculum(array('idnumber' => 'testcurriculumidnumber')); $curriculum->save(); $track = new track(array('curid' => $curriculum->id, 'idnumber' => 'testtrackidnumber')); $track->save(); if ($assigntracktoclass) { // Assign the test track to the test class instance. $trackassignment = new trackassignment(array('trackid' => $track->id, 'classid' => $pmclass->id, 'autoenrol' => 1)); $trackassignment->save(); } // Set up the test userset. $userset = new userset(); $usersetdata = array('name' => 'testusersetname'); if ($initusersetfielddata) { $usersetdata['field_userset_group'] = 1; $usersetdata['field_userset_groupings'] = 1; } $userset->set_from_data((object) $usersetdata); $userset->save(); // Assign the test user to the test track. $usertrack = new usertrack(array('userid' => $user->id, 'trackid' => $track->id)); $usertrack->save(); $clustertrack = new clustertrack(array('clusterid' => $userset->id, 'trackid' => $track->id)); $clustertrack->save(); if ($assignusertouserset) { // Assign the test user to the test userset. $clusterassignment = new clusterassignment(array('userid' => $user->id, 'clusterid' => $userset->id, 'plugin' => 'manual')); $clusterassignment->save(); } if ($initclusterprofile) { // Set up a file we can use to auto-associate users to a userset. $field = new field(array('categoryid' => $fieldcategory->id, 'shortname' => 'autoassociate', 'name' => 'autoassociate', 'datatype' => 'bool')); $field->save(); // Ensure manual field owner exists for syncing. field_owner::ensure_field_owner_exists($field, 'manual'); $ownerid = $DB->get_field(field_owner::TABLE, 'id', array('fieldid' => $field->id, 'plugin' => 'manual')); $owner = new field_owner($ownerid); $owner->param_control = 'checkbox'; $owner->save(); field_owner::ensure_field_owner_exists($field, 'moodle_profile'); $DB->execute("UPDATE {" . field_owner::TABLE . "} SET exclude = ?", array(pm_moodle_profile::sync_to_moodle)); $fieldcontextlevel = new field_contextlevel(array('fieldid' => $field->id, 'contextlevel' => CONTEXT_ELIS_USER)); $fieldcontextlevel->save(); // The associated Moodle user profile field. require_once $CFG->dirroot . '/user/profile/definelib.php'; require_once $CFG->dirroot . '/user/profile/field/checkbox/define.class.php'; $profiledefinecheckbox = new profile_define_checkbox(); $data = new stdClass(); $data->datatype = 'checkbox'; $data->categoryid = 99999; $data->shortname = 'autoassociate'; $data->name = 'autoassociate'; $profiledefinecheckbox->define_save($data); $mfield = $DB->get_record('user_info_field', array('shortname' => 'autoassociate')); // The "cluster-profile" association. $usersetprofile = new userset_profile(array('clusterid' => $userset->id, 'fieldid' => $mfield->id, 'value' => true)); $usersetprofile->save(); } // Enrol the user in the Moodle course. $mdluserid = $DB->get_field('user', 'id', array('username' => 'testuserusername')); $roleid = create_role('testrole', 'testrole', 'testrole'); enrol_try_internal_enrol($course->id, $mdluserid, $roleid); // Set up the necessary config data. set_config('userset_groups', 1, 'elisprogram_usetgroups'); set_config('siteguest', ''); // Validate setup. $this->assertEquals(0, $DB->count_records('groups')); }