From a70eb30fa9e5a6912ad8b0bb532f5b3853207606 Mon Sep 17 00:00:00 2001 From: Sam Hemelryk Date: Wed, 7 Jul 2010 02:46:34 +0000 Subject: [PATCH] enrol MDL-22854 New ajaxified enrolment interface --- enrol/ajax.php | 172 ++++ enrol/locallib.php | 747 ++++++++++++++++++ enrol/renderer.php | 593 ++++++++++++++ enrol/users.php | 546 +++---------- enrol/users_forms.php | 9 +- .../assets/skins/sam/enrolmentmanager.css | 71 ++ .../assets/skins/sam/sprite.png | Bin 0 -> 1002 bytes .../yui/enrolmentmanager/enrolmentmanager.js | 493 ++++++++++++ .../assets/skins/sam/rolemanager.css | 8 + .../rolemanager/assets/skins/sam/sprite.png | Bin 0 -> 1002 bytes enrol/yui/rolemanager/rolemanager.js | 389 +++++++++ lang/en/enrol.php | 13 + lib/ajax/getnavbranch.php | 2 + pix/t/enroladd.gif | Bin 0 -> 288 bytes theme/base/style/core.css | 23 + theme/standard/style/core.css | 22 + 16 files changed, 2658 insertions(+), 430 deletions(-) create mode 100644 enrol/ajax.php create mode 100644 enrol/locallib.php create mode 100644 enrol/renderer.php create mode 100644 enrol/yui/enrolmentmanager/assets/skins/sam/enrolmentmanager.css create mode 100644 enrol/yui/enrolmentmanager/assets/skins/sam/sprite.png create mode 100644 enrol/yui/enrolmentmanager/enrolmentmanager.js create mode 100644 enrol/yui/rolemanager/assets/skins/sam/rolemanager.css create mode 100644 enrol/yui/rolemanager/assets/skins/sam/sprite.png create mode 100644 enrol/yui/rolemanager/rolemanager.js create mode 100644 pix/t/enroladd.gif diff --git a/enrol/ajax.php b/enrol/ajax.php new file mode 100644 index 00000000000..5681b7febbc --- /dev/null +++ b/enrol/ajax.php @@ -0,0 +1,172 @@ +. + +/** + * This file processes AJAX enrolment actions and returns JSON + * + * @package moodlecore + * @copyright 2010 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define('AJAX_SCRIPT', true); + +require('../config.php'); +require_once("$CFG->dirroot/enrol/locallib.php"); +require_once("$CFG->dirroot/enrol/renderer.php"); +require_once("$CFG->dirroot/group/lib.php"); + +// Must have the sesskey +require_sesskey(); +$id = required_param('id', PARAM_INT); // course id +$action = required_param('action', PARAM_ACTION); + +$PAGE->set_url(new moodle_url('/enrol/ajax.php', array('id'=>$id, 'action'=>$action))); + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); + +if ($course->id == SITEID) { + redirect(new moodle_url('/')); +} + +require_login($course); +require_capability('moodle/course:enrolreview', $context); + +$manager = new course_enrolment_manager($course); + +$outcome = new stdClass; +$outcome->success = false; +$outcome->response = new stdClass; +$outcome->error = ''; + +if (!confirm_sesskey()) { + $outcome->error = 'invalidsesskey'; + echo json_encode($outcome); + die(); +} + +switch ($action) { + case 'unenrol': + + $ue = $DB->get_record('user_enrolments', array('id'=>required_param('ue', PARAM_INT)), '*', MUST_EXIST); + if ($manager->unenrol_user($ue)) { + $outcome->success = true; + } else { + $outcome->error = 'unabletounenrol'; + } + break; + case 'unassign': + $role = required_param('role', PARAM_INT); + $user = required_param('user', PARAM_INT); + if ($manager->unassign_role_from_user($user, $role)) { + $outcome->success = true; + } else { + $outcome->error = 'unabletounassign'; + } + break; + + case 'assign': + + $user = required_param('user', PARAM_INT); + $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST); + $roleid = required_param('roleid', PARAM_INT); + + if (!is_enrolled($context, $user)) { + $outcome->error = 'mustbeenrolled'; + break; // no roles without enrolments here in this script + } + + if ($manager->assign_role_to_user($roleid, $user->id)) { + $outcome->success = true; + $outcome->response->roleid = $roleid; + } else { + $outcome->error = 'unabletoassign'; + } + break; + + case 'getassignable': + $outcome->success = true; + $outcome->response = $manager->get_assignable_roles(); + break; + + case 'searchusers': + $enrolid = required_param('enrolid', PARAM_INT); + $search = optional_param('search', '', PARAM_CLEAN); + $page = optional_param('page', 0, PARAM_INT); + $outcome->response = $manager->get_potential_users($enrolid, $search, false, $page); + foreach ($outcome->response['users'] as &$user) { + $user->picture = $OUTPUT->user_picture($user); + $user->fullname = fullname($user); + } + $outcome->success = true; + + break; + + case 'enrol': + $enrolid = required_param('enrolid', PARAM_INT); + $userid = required_param('userid', PARAM_INT); + + $roleid = optional_param('role', null, PARAM_INT); + $duration = optional_param('duration', 0, PARAM_INT); + $startdate = optional_param('startdate', 0, PARAM_INT); + if (empty($roleid)) { + $roleid = null; + } + + switch($startdate) { + case 2: + $timestart = $course->startdate; + break; + case 3: + default: + $today = time(); + $today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0); + $timestart = $today; + break; + } + if ($duration <= 0) { + $timestart = 0; + $timeend = 0; + } else { + $timeend = $timestart + ($duration*24*60*60); + } + + $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST); + $instances = $manager->get_enrolment_instances(); + $plugins = $manager->get_enrolment_plugins(); + if (!array_key_exists($enrolid, $instances)) { + $outcome->error = 'invalidinstance'; + break; + } + $instance = $instances[$enrolid]; + $plugin = $plugins[$instance->enrol]; + try { + $plugin->enrol_user($instance, $user->id, $roleid, $timestart, $timeend); + } catch (Exception $e) { + $outcome->error = 'unabletoenrol'; + break; + } + $outcome->success = true; + break; + + default: + $outcome->error = 'unknownaction'; + break; +} + +echo json_encode($outcome); +die(); \ No newline at end of file diff --git a/enrol/locallib.php b/enrol/locallib.php new file mode 100644 index 00000000000..830c2c22149 --- /dev/null +++ b/enrol/locallib.php @@ -0,0 +1,747 @@ +. + +/** + * This file contains the course_enrolment_manager class which is used to interface + * with the functions that exist in enrollib.php in relation to a single course. + * + * @package moodlecore + * @copyright 2010 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * This class provides a targeted tied together means of interfacing the enrolment + * tasks together with a course. + * + * It is provided as a convenience more than anything else. + * + * @copyright 2010 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class course_enrolment_manager { + + /** + * The course context + * @var stdClass + */ + protected $context; + /** + * The course we are managing enrolments for + * @var stdClass + */ + protected $course = null; + /** + * Limits the focus of the manager to one enrolment plugin instance + * @var string + */ + protected $instancefilter = null; + + /** + * The total number of users enrolled in the course + * Populated by course_enrolment_manager::get_total_users + * @var int + */ + protected $totalusers = null; + /** + * An array of users currently enrolled in the course + * Populated by course_enrolment_manager::get_users + * @var array + */ + protected $users = array(); + + /**#@+ + * These variables are used to cache the information this class uses + * please never use these directly instead use thier get_ counterparts. + * @access private + * @var array + */ + private $_instancessql = null; + private $_instances = null; + private $_inames = null; + private $_plugins = null; + private $_roles = null; + private $_assignableroles = null; + private $_groups = null; + /**#@-*/ + + /** + * Constructs the course enrolment manager + * + * @param stdClass $course + * @param string $instancefilter + */ + public function __construct($course, $instancefilter = null) { + $this->context = get_context_instance(CONTEXT_COURSE, $course->id); + $this->course = $course; + $this->instancefilter = $instancefilter; + } + + /** + * Returns the total number of enrolled users in the course. + * + * If a filter was specificed this will be the total number of users enrolled + * in this course by means of that instance. + * + * @global moodle_database $DB + * @return int + */ + public function get_total_users() { + global $DB; + if ($this->totalusers === null) { + list($instancessql, $params, $filter) = $this->get_instance_sql(); + $sqltotal = "SELECT COUNT(DISTINCT u.id) + FROM {user} u + JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql) + JOIN {enrol} e ON (e.id = ue.enrolid)"; + $this->totalusers = (int)$DB->count_records_sql($sqltotal, $params); + } + return $this->totalusers; + } + + /** + * Gets all of the users enrolled in this course. + * + * If a filter was specificed this will be the users who were enrolled + * in this course by means of that instance. + * + * @global moodle_database $DB + * @param string $sort + * @param string $direction ASC or DESC + * @param int $page First page should be 0 + * @param int $perpage Defaults to 25 + * @return array + */ + public function get_users($sort, $direction='ASC', $page=0, $perpage=25) { + global $DB; + if ($direction !== 'ASC') { + $direction = 'DESC'; + } + $key = md5("$sort-$direction-$page-$perpage"); + if (!array_key_exists($key, $this->users)) { + list($instancessql, $params, $filter) = $this->get_instance_sql(); + $sql = "SELECT DISTINCT u.*, ul.timeaccess AS lastseen + FROM {user} u + JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql) + JOIN {enrol} e ON (e.id = ue.enrolid) + LEFT JOIN {user_lastaccess} ul ON (ul.courseid = e.courseid AND ul.userid = u.id)"; + if ($sort === 'firstname') { + $sql .= " ORDER BY u.firstname $direction, u.lastname $direction"; + } else if ($sort === 'lastname') { + $sql .= " ORDER BY u.lastname $direction, u.firstname $direction"; + } else if ($sort === 'email') { + $sql .= " ORDER BY u.email $direction, u.lastname $direction, u.firstname $direction"; + } else if ($sort === 'lastseen') { + $sql .= " ORDER BY ul.timeaccess $direction, u.lastname $direction, u.firstname $direction"; + } + $this->users[$key] = $DB->get_records_sql($sql, $params, $page*$perpage, $perpage); + } + return $this->users[$key]; + } + + /** + * Gets an array of the users that can be enrolled in this course. + * + * @global moodle_database $DB + * @param int $enrolid + * @param string $search + * @param bool $searchanywhere + * @param int $page Defaults to 0 + * @param int $perpage Defaults to 25 + * @return array Array(totalusers => int, users => array) + */ + public function get_potential_users($enrolid, $search='', $searchanywhere=false, $page=0, $perpage=25) { + global $DB; + + // Add some additional sensible conditions + $tests = array("u.username <> 'guest'", 'u.deleted = 0', 'u.confirmed = 1'); + $params = array(); + if (!empty($search)) { + $conditions = array('u.firstname','u.lastname'); + $ilike = ' ' . $DB->sql_ilike(); + if ($searchanywhere) { + $searchparam = '%' . $search . '%'; + } else { + $searchparam = $search . '%'; + } + $i = 0; + foreach ($conditions as &$condition) { + $condition .= "$ilike :con{$i}00"; + $params["con{$i}00"] = $searchparam; + $i++; + } + $tests[] = '(' . implode(' OR ', $conditions) . ')'; + } + $wherecondition = implode(' AND ', $tests); + + $ufields = user_picture::fields('u'); + + $fields = 'SELECT u.id, u.firstname, u.lastname, u.username, u.email, u.lastaccess, u.picture, u.imagealt, '.$ufields; + $countfields = 'SELECT COUNT(1)'; + $sql = " FROM {user} u + WHERE $wherecondition + AND u.id NOT IN (SELECT ue.userid + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.id = :enrolid))"; + $order = ' ORDER BY u.lastname ASC, u.firstname ASC'; + $params['enrolid'] = $enrolid; + $totalusers = $DB->count_records_sql($countfields . $sql, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, $params, $page*$perpage, $perpage); + return array('totalusers'=>$totalusers, 'users'=>$availableusers); + } + + /** + * Gets an array containing some SQL to user for when selecting, params for + * that SQL, and the filter that was used in constructing the sql. + * + * @global moodle_database $DB + * @return string + */ + protected function get_instance_sql() { + global $DB; + if ($this->_instancessql === null) { + $instances = $this->get_enrolment_instances(); + $filter = $this->get_enrolment_filter(); + if ($filter && array_key_exists($filter, $instances)) { + $sql = " = :ifilter"; + $params = array('ifilter'=>$filter); + } else { + $filter = 0; + if ($instances) { + list($sql, $params) = $DB->get_in_or_equal(array_keys($this->get_enrolment_instances()), SQL_PARAMS_NAMED); + } else { + // no enabled instances, oops, we should probably say something + $sql = "= :never"; + $params = array('never'=>-1); + } + } + $this->instancefilter = $filter; + $this->_instancessql = array($sql, $params, $filter); + } + return $this->_instancessql; + } + + /** + * Returns all of the enrolment instances for this course. + * + * @return array + */ + public function get_enrolment_instances() { + if ($this->_instances === null) { + $this->_instances = enrol_get_instances($this->course->id, true); + } + return $this->_instances; + } + + /** + * Returns the names for all of the enrolment instances for this course. + * + * @return array + */ + public function get_enrolment_instance_names() { + if ($this->_inames === null) { + $instances = $this->get_enrolment_instances(); + $plugins = $this->get_enrolment_plugins(); + foreach ($instances as $key=>$instance) { + if (!isset($plugins[$instance->enrol])) { + // weird, some broken stuff in plugin + unset($instances[$key]); + continue; + } + $this->_inames[$key] = $plugins[$instance->enrol]->get_instance_name($instance); + } + } + return $this->_inames; + } + + /** + * Gets all of the enrolment plugins that are active for this course. + * + * @return array + */ + public function get_enrolment_plugins() { + if ($this->_plugins === null) { + $this->_plugins = enrol_get_plugins(true); + } + return $this->_plugins; + } + + /** + * Gets all of the roles this course can contain. + * + * @return array + */ + public function get_all_roles() { + if ($this->_roles === null) { + $this->_roles = role_fix_names(get_all_roles(), $this->context); + } + return $this->_roles; + } + + /** + * Gets all of the assignable roles for this course. + * + * @return array + */ + public function get_assignable_roles() { + if ($this->_assignableroles === null) { + $this->_assignableroles = get_assignable_roles($this->context, ROLENAME_ALIAS, false); // verifies unassign access control too + } + return $this->_assignableroles; + } + + /** + * Gets all of the groups for this course. + * + * @return array + */ + public function get_all_groups() { + if ($this->_groups === null) { + $this->_groups = groups_get_all_groups($this->course->id); + foreach ($this->_groups as $gid=>$group) { + $this->_groups[$gid]->name = format_string($group->name); + } + } + return $this->_groups; + } + + /** + * Unenroles a user from the course given the users ue entry + * + * @global moodle_database $DB + * @param stdClass $ue + * @return bool + */ + public function unenrol_user($ue) { + global $DB; + + $instances = $this->get_enrolment_instances(); + $plugins = $this->get_enrolment_plugins(); + + $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST); + + if (!isset($instances[$ue->enrolid])) { + return false; + } + $instance = $instances[$ue->enrolid]; + $plugin = $plugins[$instance->enrol]; + if (!$plugin->allow_unenrol($instance) || !has_capability("enrol/$instance->enrol:unenrol", $this->context)) { + return false; + } + $plugin->unenrol_user($instance, $ue->userid); + 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; + $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST); + try { + role_unassign($roleid, $user->id, $this->context->id, '', NULL); + } catch (Exception $e) { + return false; + } + return true; + } + + /** + * Assigns a role to a user. + * + * @param int $roleid + * @param int $userid + * @return int|false + */ + public function assign_role_to_user($roleid, $userid) { + require_capability('moodle/role:assign', $this->context); + return role_assign($roleid, $userid, $this->context->id, '', NULL); + } + + /** + * Adds a user to a group + * + * @param stdClass $user + * @param int $groupid + * @return bool + */ + public function add_user_to_group($user, $groupid) { + require_capability('moodle/course:managegroups', $this->context); + $group = $this->get_group($groupid); + if (!$group) { + return false; + } + return groups_add_member($group->id, $user->id); + } + + /** + * Removes a user from a group + * + * @global moodle_database $DB + * @param StdClass $user + * @param int $groupid + * @return bool + */ + public function remove_user_from_group($user, $groupid) { + global $DB; + require_capability('moodle/course:managegroups', $this->context); + $group = $this->get_group($groupid); + if (!$group) { + return false; + } + return groups_remove_member($group, $user); + } + + /** + * Gets the requested group + * + * @param int $groupid + * @return stdClass|int + */ + public function get_group($groupid) { + $groups = $this->get_all_groups(); + if (!array_key_exists($groupid, $groups)) { + return false; + } + return $groups[$groupid]; + } + + /** + * Edits an enrolment + * + * @param stdClass $userenrolment + * @param stdClass $data + * @return bool + */ + public function edit_enrolment($userenrolment, $data) { + $instances = $this->get_enrolment_instances(); + if (!array_key_exists($userenrolment->enrolid, $instances)) { + return false; + } + $instance = $instances[$userenrolment->enrolid]; + + $plugins = $this->get_enrolment_plugins(); + $plugin = $plugins[$instance->enrol]; + if (!$plugin->allow_unenrol($instance) || !has_capability("enrol/$instance->enrol:unenrol", $this->context)) { + return false; + } + + if (!isset($data->status)) { + $data->status = $userenrolment->status; + } + + $plugin->update_user_enrol($instance, $userenrolment->userid, $data->status, $data->timestart, $data->timeend); + return true; + } + + /** + * Returns the current enrolment filter that is being applied by this class + * @return string + */ + public function get_enrolment_filter() { + return $this->instancefilter; + } + + /** + * Gets the roles assigned to this user that are applicable for this course. + * + * @param int $userid + * @return array + */ + public function get_user_roles($userid) { + $roles = array(); + $ras = get_user_roles($this->context, $userid, true, 'c.contextlevel DESC, r.sortorder ASC'); + foreach ($ras as $ra) { + if ($ra->contextid != $this->context->id) { + if (!array_key_exists($ra->roleid, $roles)) { + $roles[$ra->roleid] = null; + } + // higher ras, course always takes precedence + continue; + } + if (array_key_exists($ra->roleid, $roles) && $roles[$ra->roleid] === false) { + continue; + } + $roles[$ra->roleid] = ($ra->itemid == 0 and $ra->component === ''); + } + return $roles; + } + + /** + * Gets the enrolments this user has in the course + * + * @global moodle_database $DB + * @param int $userid + * @return array + */ + public function get_user_enrolments($userid) { + global $DB; + list($instancessql, $params, $filter) = $this->get_instance_sql(); + $params['userid'] = $userid; + $userenrolments = $DB->get_records_select('user_enrolments', "enrolid $instancessql AND userid = :userid", $params); + $instances = $this->get_enrolment_instances(); + $plugins = $this->get_enrolment_plugins(); + $inames = $this->get_enrolment_instance_names(); + foreach ($userenrolments as &$ue) { + $ue->enrolmentinstance = $instances[$ue->enrolid]; + $ue->enrolmentplugin = $plugins[$ue->enrolmentinstance->enrol]; + $ue->enrolmentinstancename = $inames[$ue->enrolmentinstance->id]; + } + return $userenrolments; + } + + /** + * Gets the groups this user belongs to + * + * @param int $userid + * @return array + */ + public function get_user_groups($userid) { + return groups_get_all_groups($this->course->id, $userid, 0, 'g.id'); + } + + /** + * Retursn an array of params that would go into the URL to return to this + * exact page. + * + * @return array + */ + public function get_url_params() { + $args = array( + 'id' => $this->course->id + ); + if (!empty($this->instancefilter)) { + $args['ifilter'] = $this->instancefilter; + } + return $args; + } + + /** + * Returns the course this object is managing enrolments for + * + * @return stdClass + */ + public function get_course() { + return $this->course; + } + + /** + * Returns the course context + * + * @return stdClass + */ + public function get_context() { + return $this->context; + } + + /** + * Gets an array of users for display, this includes minimal user information + * as well as minimal information on the users roles, groups, and enrolments. + * + * @param core_enrol_renderer $renderer + * @param moodle_url $pageurl + * @param int $sort + * @param string $direction ASC or DESC + * @param int $page + * @param int $perpage + * @return array + */ + public function get_users_for_display(core_enrol_renderer $renderer, moodle_url $pageurl, $sort, $direction, $page, $perpage) { + $users = $this->get_users($sort, $direction, $page, $perpage); + + $now = time(); + $strnever = get_string('never'); + $straddgroup = get_string('addgroup', 'group'); + $strunenrol = get_string('unenrol', 'enrol'); + $stredit = get_string('edit'); + + $iconedit = $renderer->pix_url('t/edit'); + $iconenroladd = $renderer->pix_url('t/enroladd'); + $iconenrolremove = $renderer->pix_url('t/delete'); + + $allroles = $this->get_all_roles(); + $assignable = $this->get_assignable_roles(); + $allgroups = $this->get_all_groups(); + $courseid = $this->get_course()->id; + $context = $this->get_context(); + $canmanagegroups = has_capability('moodle/course:managegroups', $context); + + $url = new moodle_url($pageurl, $this->get_url_params()); + + $userdetails = array(); + foreach ($users as $user) { + $details = array( + 'userid' => $user->id, + 'courseid' => $courseid, + 'picture' => new user_picture($user), + 'firstname' => fullname($user, true), + 'email' => $user->email, + 'lastseen' => $strnever, + 'roles' => array(), + 'groups' => array(), + 'enrolments' => array() + ); + + if ($user->lastseen) { + $details['lastseen'] = format_time($user->lastaccess); + } + + // Roles + foreach ($this->get_user_roles($user->id) as $rid=>$rassignable) { + $details['roles'][$rid] = array('text'=>$allroles[$rid]->localname, 'unchangeable'=>(!$rassignable || !isset($assignable[$rid]))); + } + + // Users + $usergroups = $this->get_user_groups($user->id); + foreach($usergroups as $gid=>$unused) { + $details['groups'][$gid] = $allgroups[$gid]->name; + } + + // Enrolments + foreach ($this->get_user_enrolments($user->id) as $ue) { + if ($ue->timestart and $ue->timeend) { + $period = get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend))); + $periodoutside = ($ue->timestart && $ue->timeend && $now < $ue->timestart && $now > $ue->timeend); + } else if ($ue->timestart) { + $period = get_string('periodstart', 'enrol', userdate($ue->timestart)); + $periodoutside = ($ue->timestart && $now < $ue->timestart); + } else if ($ue->timeend) { + $period = get_string('periodend', 'enrol', userdate($ue->timeend)); + $periodoutside = ($ue->timeend && $now > $ue->timeend); + } else { + $period = ''; + $periodoutside = false; + } + $details['enrolments'][$ue->id] = array( + 'text' => $ue->enrolmentinstancename, + 'period' => $period, + 'dimmed' => ($periodoutside || $ue->status != ENROL_USER_ACTIVE), + 'canunenrol' => ($ue->enrolmentplugin->allow_unenrol($ue->enrolmentinstance) && has_capability("enrol/".$ue->enrolmentinstance->enrol.":unenrol", $context)), + 'canmanage' => ($ue->enrolmentplugin->allow_manage($ue->enrolmentinstance) && has_capability("enrol/".$ue->enrolmentinstance->enrol.":manage", $context)) + ); + } + $userdetails[$user->id] = $details; + } + return $userdetails; + + if (1==2){ + // get list of roles + $roles = $this->get_user_roles($user->id); + foreach ($roles as $rid=>$unassignable) { + if ($unassignable && isset($assignable[$rid])) { + $icon = html_writer::empty_tag('img', array('alt'=>get_string('unassignarole', 'role', $allroles[$rid]->localname), 'src'=>$iconenrolremove)); + $url = new moodle_url($url, array('action'=>'unassign', 'role'=>$rid, 'user'=>$user->id)); + $roles[$rid] = html_writer::tag('div', $allroles[$rid]->localname . html_writer::link($url, $icon, array('class'=>'unassignrolelink', 'rel'=>$rid)), array('class'=>'role role_'.$rid)); + } else { + $roles[$rid] = html_writer::tag('div', $allroles[$rid]->localname, array('class'=>'role unchangeable', 'rel'=>$rid)); + } + } + $addrole = ''; + if ($assignable) { + foreach ($assignable as $rid=>$unused) { + if (!isset($roles[$rid])) { + //candidate for role assignment + $url = new moodle_url($url, array('action'=>'assign', 'user'=>$user->id)); + $icon = html_writer::empty_tag('img', array('alt'=>get_string('assignroles', 'role', $allroles[$rid]->localname), 'src'=>$iconenroladd)); + $addrole .= html_writer::link($url, $icon, array('class'=>'assignrolelink')); + break; + } + } + } + $roles = html_writer::tag('div', implode('', $roles), array('class'=>'roles')); + if ($addrole) { + $roles = html_writer::tag('div', $addrole, array('class'=>'addrole')).$roles; + } + + // Get list of groups + $usergroups = $this->get_user_groups($user->id); + $groups = array(); + foreach($usergroups as $gid=>$unused) { + $group = $allgroups[$gid]; + if ($canmanagegroups) { + $icon = html_writer::empty_tag('img', array('alt'=>get_string('removefromgroup', 'group', $group->name), 'src'=>$iconenrolremove)); + $url = new moodle_url($url, array('action'=>'removemember', 'group'=>$gid, 'user'=>$user->id)); + $groups[] = $group->name . html_writer::link($url, $icon); + } else { + $groups[] = $group->name; + } + } + $groups = implode(', ', $groups); + if ($canmanagegroups and (count($usergroups) < count($allgroups))) { + $icon = html_writer::empty_tag('img', array('alt'=>$straddgroup, 'src'=>$iconenroladd)); + $url = new moodle_url($url, array('action'=>'addmember', 'user'=>$user->id)); + $groups .= '
'.html_writer::link($url, $icon).'
'; + } + + + // get list of enrol instances + $ues = $this->get_user_enrolments($user->id); + $edits = array(); + foreach ($ues as $ue) { + $edit = $ue->enrolmentinstancename; + + $dimmed = false; + if ($ue->timestart and $ue->timeend) { + $edit .= ' ('.get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend))).')'; + $dimmed = ($now < $ue->timestart and $now > $ue->timeend); + } else if ($ue->timestart) { + $edit .= ' ('.get_string('periodstart', 'enrol', userdate($ue->timestart)).')'; + $dimmed = ($now < $ue->timestart); + } else if ($ue->timeend) { + $edit .= ' ('.get_string('periodend', 'enrol', userdate($ue->timeend)).')'; + $dimmed = ($now > $ue->timeend); + } + + if ($dimmed or $ue->status != ENROL_USER_ACTIVE) { + $edit = html_writer::tag('span', $edit, array('class'=>'dimmed_text')); + } + + if ($ue->enrolmentplugin->allow_unenrol($ue->enrolmentinstance) && has_capability("enrol/".$ue->enrolmentinstance->enrol.":unenrol", $context)) { + $icon = html_writer::empty_tag('img', array('alt'=>$strunenrol, 'src'=>$iconenrolremove)); + $url = new moodle_url($url, array('action'=>'unenrol', 'ue'=>$ue->id)); + $edit .= html_writer::link($url, $icon, array('class'=>'unenrollink', 'rel'=>$ue->id)); + } + + if ($ue->enrolmentplugin->allow_manage($ue->enrolmentinstance) && has_capability("enrol/".$ue->enrolmentinstance->enrol.":manage", $context)) { + $icon = html_writer::empty_tag('img', array('alt'=>$stredit, 'src'=>$iconedit)); + $url = new moodle_url($url, array('action'=>'edit', 'ue'=>$ue->id)); + $edit .= html_writer::link($url, $icon, array('class'=>'editenrollink', 'rel'=>$ue->id)); + } + + $edits[] = html_writer::tag('div', $edit, array('class'=>'enrolment')); + } + $edits = implode('', $edits); + + + $userdetails[$user->id] = array( + 'picture' => $renderer->user_picture($user, array('courseid'=>$courseid)), + 'firstname' => html_writer::link(new moodle_url('/user/view.php', array('id'=>$user->id, 'course'=>$courseid)), fullname($user, true)), + 'email' => $user->email, + 'lastseen' => $strlastaccess, + 'role' => $roles, + 'group' => $groups, + 'enrol' => $edits + ); + } + return $userdetails; + } +} \ No newline at end of file diff --git a/enrol/renderer.php b/enrol/renderer.php new file mode 100644 index 00000000000..d51a064cae1 --- /dev/null +++ b/enrol/renderer.php @@ -0,0 +1,593 @@ +. + +/** + * This is the main renderer for the enrol section. + * + * @package moodlecore + * @copyright 2010 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * This is the core renderer + * + * @copyright 2010 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class core_enrol_renderer extends plugin_renderer_base { + + /** + * Renders a course enrolment table + * + * @param course_enrolment_table $table + * @return string + */ + protected function render_course_enrolment_table(course_enrolment_table $table) { + $content = ''; + $enrolmentselector = $table->get_enrolment_selector($this->page); + if ($enrolmentselector) { + $content .= $this->output->render($enrolmentselector); + } + $content .= $this->output->render($table->get_enrolment_type_filter()); + $content .= $this->output->render($table->get_paging_bar()); + $content .= html_writer::table($table); + $content .= $this->output->render($table->get_paging_bar()); + $enrolmentselector = $table->get_enrolment_selector($this->page); + if ($enrolmentselector) { + $content .= $this->output->render($enrolmentselector); + } + return $content; + } + + /** + * Generates HTML to display the users roles and any available actions + * + * @param int $userid + * @param array $roles + * @param array $assignableroles + * @param moodle_url $pageurl + * @return string + */ + public function user_roles_and_actions($userid, $roles, $assignableroles, $canassign, $pageurl) { + $iconenroladd = $this->output->pix_url('t/enroladd'); + $iconenrolremove = $this->output->pix_url('t/delete'); + + // get list of roles + $rolesoutput = ''; + foreach ($roles as $roleid=>$role) { + if ($canassign && !$role['unchangeable']) { + $strunassign = get_string('unassignarole', 'role', $role['text']); + $icon = html_writer::empty_tag('img', array('alt'=>$strunassign, 'src'=>$iconenrolremove)); + $url = new moodle_url($pageurl, array('action'=>'unassign', 'role'=>$roleid, 'user'=>$userid)); + $rolesoutput .= html_writer::tag('div', $role['text'] . html_writer::link($url, $icon, array('class'=>'unassignrolelink', 'rel'=>$roleid, 'title'=>$strunassign)), array('class'=>'role role_'.$roleid)); + } else { + $rolesoutput .= html_writer::tag('div', $role['text'], array('class'=>'role unchangeable', 'rel'=>$roleid)); + } + } + $output = ''; + if (!empty($assignableroles) && $canassign) { + $roleids = array_keys($roles); + $hasallroles = true; + foreach (array_keys($assignableroles) as $key) { + if (!in_array($key, $roleids)) { + $hasallroles = false; + break; + } + } + if (!$hasallroles) { + $url = new moodle_url($pageurl, array('action'=>'assign', 'user'=>$userid)); + $icon = html_writer::empty_tag('img', array('alt'=>get_string('assignroles', 'role'), 'src'=>$iconenroladd)); + $output = html_writer::tag('div', html_writer::link($url, $icon, array('class'=>'assignrolelink', 'title'=>get_string('assignroles', 'role'))), array('class'=>'addrole')); + } + } + $output .= html_writer::tag('div', $rolesoutput, array('class'=>'roles')); + return $output; + } + + /** + * Generates the HTML to view the users groups and available group actions + * + * @param int $userid + * @param array $groups + * @param array $allgroups + * @param bool $canmanagegroups + * @param moodle_url $pageurl + * @return string + */ + public function user_groups_and_actions($userid, $groups, $allgroups, $canmanagegroups, $pageurl) { + $iconenroladd = $this->output->pix_url('t/enroladd'); + $iconenrolremove = $this->output->pix_url('t/delete'); + $straddgroup = get_string('addgroup', 'group'); + + $groupoutput = ''; + foreach($groups as $groupid=>$name) { + if ($canmanagegroups) { + $icon = html_writer::empty_tag('img', array('alt'=>get_string('removefromgroup', 'group', $name), 'src'=>$iconenrolremove)); + $url = new moodle_url($pageurl, array('action'=>'removemember', 'group'=>$groupid, 'user'=>$userid)); + $groupoutput .= html_writer::tag('div', $name . html_writer::link($url, $icon), array('class'=>'group', 'rel'=>$groupid)); + } else { + $groupoutput .= html_writer::tag('div', $name, array('class'=>'group', 'rel'=>$groupid)); + } + } + $groupoutput = html_writer::tag('div', $groupoutput, array('class'=>'groups')); + if ($canmanagegroups && (count($groups) < count($allgroups))) { + $icon = html_writer::empty_tag('img', array('alt'=>$straddgroup, 'src'=>$iconenroladd)); + $url = new moodle_url($pageurl, array('action'=>'addmember', 'user'=>$userid)); + $groupoutput .= html_writer::tag('div', html_writer::link($url, $icon), array('class'=>'addgroup')); + } + return $groupoutput; + } + + /** + * Generates the HTML for the given enrolments + available actions + * + * @param int $userid + * @param array $enrolments + * @param moodle_url $pageurl + * @return string + */ + public function user_enrolments_and_actions($userid, $enrolments, $pageurl) { + $iconedit = $this->output->pix_url('t/edit'); + $iconenrolremove = $this->output->pix_url('t/delete'); + $strunenrol = get_string('unenrol', 'enrol'); + $stredit = get_string('edit'); + + $output = ''; + foreach ($enrolments as $ueid=>$enrolment) { + $enrolmentoutput = $enrolment['text'].' '.$enrolment['period']; + if ($enrolment['dimmed']) { + $enrolmentoutput = html_writer::tag('span', $enrolmentoutput, array('class'=>'dimmed_text')); + } + if ($enrolment['canunenrol']) { + $icon = html_writer::empty_tag('img', array('alt'=>$strunenrol, 'src'=>$iconenrolremove)); + $url = new moodle_url($pageurl, array('action'=>'unenrol', 'ue'=>$ueid)); + $enrolmentoutput .= html_writer::link($url, $icon, array('class'=>'unenrollink', 'rel'=>$ueid)); + } + if ($enrolment['canmanage']) { + $icon = html_writer::empty_tag('img', array('alt'=>$stredit, 'src'=>$iconedit)); + $url = new moodle_url($url, array('action'=>'edit', 'ue'=>$ueid)); + $enrolmentoutput .= html_writer::link($url, $icon, array('class'=>'editenrollink', 'rel'=>$ueid)); + } + $output .= html_writer::tag('div', $enrolmentoutput, array('class'=>'enrolment')); + } + return $output; + } + +} + +/** + * Main course enrolment table + * + * This table is used to display the enrolment information for a course. + * It requires that a course enrolment manager be provided during constuct with + * provides all of the information for the table. + * The control then produces the table, the paging, and the associated JS actions + * for the page. + * + * @package core + * @subpackage enrol + * @copyright 2010 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class course_enrolment_table extends html_table implements renderable { + + /** + * The get/post variable that is used to identify the page. + * Default: page + */ + const PAGEVAR = 'page'; + + /** + * The get/post variable to is used to identify the number of items to display + * per page. + * Default: perpage + */ + const PERPAGEVAR = 'perpage'; + + /** + * The get/post variable that is used to identify the sort field for the table. + * Default: sort + */ + const SORTVAR = 'sort'; + + /** + * The get/post variable that is used to identify the sort direction for the table. + * Default: dir + */ + const SORTDIRECTIONVAR = 'dir'; + + /** + * The default number of items per page. + * Default: 20 + */ + const DEFAULTPERPAGE = 20; + + /** + * The default sort, options are course_enrolment_table::$sortablefields + * Default: lastname + */ + const DEFAULTSORT = 'lastname'; + + /** + * The default direction + * Default: ASC + */ + const DEFAULTSORTDIRECTION = 'ASC'; + + /** + * The current page, starting from 0 + * @var int + */ + public $page = 0; + + /** + * The total number of pages + * @var int + */ + public $pages = 0; + + /** + * The number of items to display per page + * @var int + */ + public $perpage = 0; + + /** + * The URL of the page for this table + * @var moodle_url + */ + public $pageurl; + + /** + * The sort field for this table, should be one of course_enrolment_table::$sortablefields + * @var string + */ + public $sort; + + /** + * The sort direction, either ASC or DESC + * @var string + */ + public $sortdirection; + + /** + * The course manager this table is displaying for + * @var course_enrolment_manager + */ + protected $manager; + + /** + * The paging bar that controls the paging for this table + * @var paging_bar + */ + protected $pagingbar = null; + + /** + * The total number of users enrolled in the course + * @var int + */ + protected $totalusers = null; + + /** + * The users enrolled in this course + * @var array + */ + protected $users = null; + + /** + * The fields for this table + * @var array + */ + protected $fields = array(); + + protected static $sortablefields = array('firstname', 'lastname', 'email', 'lastaccess'); + + /** + * Constructs the table + * + * @param course_enrolment_manager $manager + */ + public function __construct(course_enrolment_manager $manager, moodle_url $pageurl) { + + $this->manager = $manager; + $this->pageurl = $pageurl; + + $this->page = optional_param(self::PAGEVAR, 0, PARAM_INT); + $this->perpage = optional_param(self::PERPAGEVAR, self::DEFAULTPERPAGE, PARAM_INT); + $this->sort = optional_param(self::SORTVAR, self::DEFAULTSORT, PARAM_ALPHA); + $this->sortdirection = optional_param(self::SORTDIRECTIONVAR, self::DEFAULTSORTDIRECTION, PARAM_ALPHA); + + $this->attributes = array('class'=>'userenrolment'); + if (!in_array($this->sort, self::$sortablefields)) { + $this->sort = self::DEFAULTSORT; + } + if ($this->page < 0) { + $this->page = 0; + } + if ($this->sortdirection !== 'ASC' && $this->sortdirection !== 'DESC') { + $this->sortdirection = self::DEFAULTSORTDIRECTION; + } + + $this->id = html_writer::random_id(); + $this->set_total_users($manager->get_total_users()); + } + + /** + * Gets the sort direction for a given field + * + * @param string $field + * @return string ASC or DESC + */ + public function get_field_sort_direction($field) { + if ($field == $this->sort) { + return ($this->sortdirection == 'ASC')?'DESC':'ASC'; + } + return self::DEFAULTSORTDIRECTION; + } + + /** + * Sets the fields for this table. These get added to the tables head as well. + * + * You can also use a multi dimensional array for this to have multiple fields + * in a single column + * + * @param array $fields An array of fields to set + * @param string $output + */ + public function set_fields($fields, $output=null) { + global $OUTPUT; + if ($output === null) { + $output = $OUTPUT; + } + $this->fields = $fields; + $this->head = array(); + $this->colclasses = array(); + $this->align = array(); + $url = new moodle_url($this->pageurl, $this->get_url_params()+$this->manager->get_url_params()); + foreach ($fields as $name => $label) { + $newlabel = ''; + if (is_array($label)) { + $bits = array(); + foreach ($label as $n => $l) { + if ($l === false) { + continue; + } + if (!in_array($n, self::$sortablefields)) { + $bits[] = $l; + } else { + $link = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n)), $fields[$name][$n]); + if ($this->sort == $n) { + $link .= ' '.html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($n))), $this->get_direction_icon($output, $n)); + } + $bits[] = html_writer::tag('span', $link, array('class'=>'subheading_'.$n)); + + } + } + $newlabel = join(' / ', $bits); + } else { + if (!in_array($name, self::$sortablefields)) { + $newlabel = $label; + } else { + $newlabel = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name)), $fields[$name]); + if ($this->sort == $name) { + $newlabel .= ' '.html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($name))), $this->get_direction_icon($output, $name)); + } + } + } + $this->head[] = $newlabel; + $this->colclasses[] = 'field col_'.$name; + } + } + /** + * Sets the total number of users + * + * @param int $totalusers + */ + public function set_total_users($totalusers) { + $this->totalusers = $totalusers; + $this->pages = ceil($this->totalusers / $this->perpage); + if ($this->page > $this->pages) { + $this->page = $this->pages; + } + } + /** + + */ + /** + * Sets the users for this table + * + * @param array $users + * @param moodle_page $page + */ + public function set_users(array $users, moodle_page $page=null) { + global $PAGE; + if ($page === null) { + $page = $PAGE; + } + foreach ($users as $userid=>$user) { + $user = (array)$user; + $row = new html_table_row(); + $row->attributes = array('class' => 'userinforow'); + $row->id = 'user_'.$userid; + $row->cells = array(); + foreach ($this->fields as $field => $label) { + if (is_array($label)) { + $bits = array(); + foreach (array_keys($label) as $subfield) { + if (array_key_exists($subfield, $user)) { + $bits[] = html_writer::tag('div', $user[$subfield], array('class'=>'subfield subfield_'.$subfield)); + } + } + if (empty($bits)) { + $bits[] = ' '; + } + $row->cells[] = new html_table_cell(join(' ', $bits)); + } else { + if (!array_key_exists($field, $user)) { + $user[$field] = ' '; + } + $row->cells[] = new html_table_cell($user[$field]); + } + } + $this->data[] = $row; + } + if (has_capability('moodle/role:assign', $this->manager->get_context())) { + $arguments = array(array('containerId'=>$this->id, 'userIds'=>array_keys($users), 'courseId'=>$this->manager->get_course()->id)); + $page->requires->yui_module(array('moodle-enrol-rolemanager', 'moodle-enrol-rolemanager-skin'), 'M.enrol.rolemanager.init', $arguments); + } + } + + /** + * Gets the paging bar instance for this table + * + * @return paging_bar + */ + public function get_paging_bar() { + if ($this->pagingbar == null) { + $this->pagingbar = new paging_bar($this->totalusers, $this->page, $this->perpage, $this->pageurl, self::PAGEVAR); + } + return $this->pagingbar; + } + + /** + * Gets the direction icon for the sortable field within this table + * + * @param core_renderer $output + * @param string $field + * @return string + */ + protected function get_direction_icon($output, $field) { + $direction = self::DEFAULTSORTDIRECTION; + if ($this->sort == $field) { + $direction = $this->sortdirection; + } + if ($direction === 'ASC') { + return html_writer::empty_tag('img', array('alt'=>'', 'src'=>$output->pix_url('t/down'))); + } else { + return html_writer::empty_tag('img', array('alt'=>'', 'src'=>$output->pix_url('t/up'))); + } + } + + /** + * Gets the params that will need to be added to the url in order to return to this page. + * + * @return array + */ + public function get_url_params() { + return array( + self::PAGEVAR => $this->page, + self::PERPAGEVAR => $this->perpage, + self::SORTVAR => $this->sort, + self::SORTDIRECTIONVAR => $this->sortdirection + ); + } + + /** + * Gets the enrolment type filter control for this table + * + * @return single_select + */ + public function get_enrolment_type_filter() { + $url = new moodle_url($this->pageurl, $this->manager->get_url_params()+$this->get_url_params()); + $selector = new single_select($url, 'ifilter', array(0=>get_string('all')) + $this->manager->get_enrolment_instance_names(), $this->manager->get_enrolment_filter(), array()); + $selector->set_label( get_string('enrolmentinstances', 'enrol')); + return $selector; + } + + /** + * Gets the enrolment selector control for this table and initialises its + * JavaScript + * + * @return single_button|url_select + */ + public function get_enrolment_selector(moodle_page $page) { + static $count = 0; + + $instances = $this->manager->get_enrolment_instances(); + $plugins = $this->manager->get_enrolment_plugins(); + // print enrol link or selection + $links = array(); + foreach($instances as $instance) { + $plugin = $plugins[$instance->enrol]; + if ($link = $plugin->get_manual_enrol_link($instance)) { + $links[$instance->id] = $link; + } + } + if (!empty($links)) { + $arguments = array(); + $count ++; + if (count($links) == 1) { + $control = new single_button(reset($links), get_string('enrolusers', 'enrol_manual'), 'get'); + $control->class = 'singlebutton enrolusersbutton instance'.$count; + $control->formid = 'manuallyenrol_single_'+$count; + $arguments[] = array('id'=>key($links), 'name'=>$plugins[$instances[key($links)]->enrol]->get_instance_name($instances[key($links)])); + } else if (count($links) > 1) { + $inames = $this->manager->get_enrolment_instance_names(); + $options = array(); + foreach ($links as $i=>$link) { + $options[$link->out(false)] = $inames[$i]; + $arguments[] = array('id'=>$i, 'name'=>$plugins[$instances[$i]->enrol]->get_instance_name($instances[$i])); + } + $control = new url_select($options, '', array(''=>get_string('enrolusers', 'enrol_manual').'...')); + $control->class = 'singlebutton enrolusersbutton instance'.$count; + $control->formid = 'manuallyenrol_select_'+$count; + } + $course = $this->manager->get_course(); + $url = new moodle_url($this->pageurl, $this->manager->get_url_params()+$this->get_url_params()); + $timeformat = get_string('strftimedatefullshort'); + $today = time(); + $today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0); + $startdateoptions = array(); + if ($course->startdate > 0) { + $startdateoptions[2] = get_string('coursestart') . ' (' . userdate($course->startdate, $timeformat) . ')'; + } + $startdateoptions[3] = get_string('today') . ' (' . userdate($today, $timeformat) . ')' ; + + if ($count == 1) { + $page->requires->strings_for_js(array( + 'ajaxoneuserfound', + 'ajaxxusersfound', + 'ajaxnext25', + 'enrol', + 'enrolmentoptions', + 'enrolusers', + 'errajaxfailedenrol', + 'errajaxsearch', + 'none', + 'usersearch', + 'unlimitedduration', + 'startdatetoday', + 'durationdays', + 'enrolperiod'), 'enrol'); + $page->requires->string_for_js('assignroles', 'role'); + $page->requires->string_for_js('startingfrom', 'moodle'); + + + $arguments = array(array( + 'instances'=>$arguments, + 'courseid'=>$course->id, + 'ajaxurl'=>'/enrol/ajax.php', + 'url'=>$url->out(false), + 'optionsStartDate'=>$startdateoptions)); + $page->requires->yui_module(array('moodle-enrol-enrolmentmanager', 'moodle-enrol-enrolmentmanager-skin'), 'M.enrol.enrolmentmanager.init', $arguments); + } + return $control; + } + return null; + } +} \ No newline at end of file diff --git a/enrol/users.php b/enrol/users.php index e2fced2c48a..15b841508f2 100644 --- a/enrol/users.php +++ b/enrol/users.php @@ -17,138 +17,80 @@ /** * Main course enrolment management UI, this is not compatible with frontpage course. * - * @package core - * @subpackage enrol + * @package moodlecore * @copyright 2010 Petr Skoda {@link http://skodak.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require('../config.php'); +require_once("$CFG->dirroot/enrol/locallib.php"); require_once("$CFG->dirroot/enrol/users_forms.php"); +require_once("$CFG->dirroot/enrol/renderer.php"); require_once("$CFG->dirroot/group/lib.php"); $id = required_param('id', PARAM_INT); // course id $action = optional_param('action', '', PARAM_ACTION); -$confirm = optional_param('confirm', 0, PARAM_BOOL); - -$ifilter = optional_param('ifilter', 0, PARAM_INT); // only one instance -$page = optional_param('page', 0, PARAM_INT); -$perpage = optional_param('perpage', 20, PARAM_INT); -$sort = optional_param('sort', 'lastname', PARAM_ALPHA); -$dir = optional_param('dir', 'ASC', PARAM_ALPHA); +$filter = optional_param('ifilter', 0, PARAM_INT); +$PAGE->set_url(new moodle_url('/enrol/users.php', array('id'=>$id))); $course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); $context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST); -require_login($course); -require_capability('moodle/course:enrolreview', $context); - if ($course->id == SITEID) { - redirect("$CFG->wwwroot/"); -} - -$managegroups = has_capability('moodle/course:managegroups', $context); -$instances = enrol_get_instances($course->id, true); -$plugins = enrol_get_plugins(true); -$inames = array(); -foreach ($instances as $k=>$i) { - if (!isset($plugins[$i->enrol])) { - // weird, some broken stuff in plugin - unset($instances[$k]); - continue; - } - $inames[$k] = $plugins[$i->enrol]->get_instance_name($i); -} - -// validate paging params -if ($ifilter != 0 and !isset($instances[$ifilter])) { - $ifilter = 0; -} -if ($perpage < 3) { - $perpage = 3; -} -if ($page < 0) { - $page = 0; -} -if (!in_array($dir, array('ASC', 'DESC'))) { - $dir = 'ASC'; -} -if (!in_array($sort, array('firstname', 'lastname', 'email', 'lastseen'))) { - $dir = 'lastname'; + redirect(new moodle_url('/')); } -$PAGE->set_url('/enrol/users.php', array('id'=>$course->id, 'page'=>$page, 'sort'=>$sort, 'dir'=>$dir, 'perpage'=>$perpage, 'ifilter'=>$ifilter)); +require_login($course); +require_capability('moodle/course:enrolreview', $context); $PAGE->set_pagelayout('admin'); -//lalala- nav hack -navigation_node::override_active_url(new moodle_url('/enrol/users.php', array('id'=>$course->id))); +$manager = new course_enrolment_manager($course, $filter); +$table = new course_enrolment_table($manager, $PAGE->url); +$pageurl = new moodle_url($PAGE->url, $manager->get_url_params()+$table->get_url_params()); +// Check if there is an action to take +if ($action) { -$allroles = get_all_roles(); -$allroles = role_fix_names($allroles, $context); -$assignable = get_assignable_roles($context, ROLENAME_ALIAS, false); // verifies unassign access control too -$allgroups = groups_get_all_groups($course->id); -foreach ($allgroups as $gid=>$group) { - $allgroups[$gid]->name = format_string($group->name); -} + // Check if the page is confirmed (and sesskey is correct) + $confirm = optional_param('confirm', false, PARAM_BOOL) && confirm_sesskey(); + + $actiontaken = false; + $pagetitle = ''; + $pageheading = ''; + $mform = null; + $pagecontent = null; -if ($action) { switch ($action) { case 'unenrol': - $ue = required_param('ue', PARAM_INT); - if (!$ue = $DB->get_record('user_enrolments', array('id'=>$ue))) { - break; - } - $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST); - if (!isset($instances[$ue->enrolid])) { - break; - } - $instance = $instances[$ue->enrolid]; - $plugin = $plugins[$instance->enrol]; - if (!$plugin->allow_unenrol($instance) or !has_capability("enrol/$instance->enrol:unenrol", $context)) { - break; - } - - if ($confirm and confirm_sesskey()) { - $plugin->unenrol_user($instance, $ue->userid); - redirect($PAGE->url); - + $ue = $DB->get_record('user_enrolments', array('id'=>required_param('ue', PARAM_INT)), '*', MUST_EXIST); + if ($confirm && $manager->unenrol_user($ue)) { + redirect($pageurl); } else { - $yesurl = new moodle_url($PAGE->url, array('action'=>'unenrol', 'ue'=>$ue->id, 'confirm'=>1, 'sesskey'=>sesskey())); + $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST); + $yesurl = new moodle_url($pageurl, array('action'=>'unenrol', 'ue'=>$ue->id, 'confirm'=>1, 'sesskey'=>sesskey())); $message = get_string('unenrolconfirm', 'enrol', array('user'=>fullname($user, true), 'course'=>format_string($course->fullname))); - $PAGE->set_title(get_string('unenrol', 'enrol')); - echo $OUTPUT->header(); - echo $OUTPUT->heading(get_string('unenrol', 'enrol')); - echo $OUTPUT->confirm($message, $yesurl, $PAGE->url); - echo $OUTPUT->footer(); - die; + $pagetitle = get_string('unenrol', 'enrol'); + $pagecontent = $OUTPUT->confirm($message, $yesurl, $pageurl); } + $actiontaken = true; break; case 'unassign': $role = required_param('role', PARAM_INT); $user = required_param('user', PARAM_INT); - if (!isset($assignable[$role])) { - break; - } - $role = $allroles[$role]; - $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST); - - if ($confirm and confirm_sesskey()) { - role_unassign($role->id, $user->id, $context->id, '', NULL); - redirect($PAGE->url); - + if ($confirm && $manager->unassign_role_from_user($user, $role)) { + redirect($pageurl); } else { - $yesurl = new moodle_url($PAGE->url, array('action'=>'unassign', 'role'=>$role->id, 'user'=>$user->id, 'confirm'=>1, 'sesskey'=>sesskey())); + $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST); + $allroles = $manager->get_all_roles(); + $role = $allroles[$role]; + $yesurl = new moodle_url($pageurl, array('action'=>'unassign', 'role'=>$role->id, 'user'=>$user->id, 'confirm'=>1, 'sesskey'=>sesskey())); $message = get_string('unassignconfirm', 'role', array('user'=>fullname($user, true), 'role'=>$role->localname)); - $PAGE->set_title(get_string('unassignarole', 'role', $role->localname)); - echo $OUTPUT->header(); - echo $OUTPUT->heading(get_string('unassignarole', 'role', $role->localname)); - echo $OUTPUT->confirm($message, $yesurl, $PAGE->url); - echo $OUTPUT->footer(); - die; + $pagetitle = get_string('unassignarole', 'role', $role->localname); + $pagecontent = $OUTPUT->confirm($message, $yesurl, $pageurl); } + $actiontaken = true; break; case 'assign': @@ -159,363 +101,119 @@ if ($action) { break; // no roles without enrolments here in this script } - $mform = new enrol_users_assign_form(NULL, array('user'=>$user, 'course'=>$course, 'assignable'=>$assignable)); - - if ($mform->is_cancelled()) { - redirect($PAGE->url); - - } else if ($data = $mform->get_data()) { - if ($data->roleid) { - role_assign($data->roleid, $user->id, $context->id, '', NULL); - } - redirect($PAGE->url); + $mform = new enrol_users_assign_form(NULL, array('user'=>$user, 'course'=>$course, 'assignable'=>$manager->get_assignable_roles())); + $mform->set_data($pageurl->params()); + $data = $mform->get_data(); + if ($mform->is_cancelled() || ($data && $manager->assign_role_to_user($data->roleid, $user->id))) { + redirect($pageurl); + } else { + $pagetitle = get_string('assignroles', 'role'); } - - $PAGE->set_title(get_string('assignroles', 'role')); - echo $OUTPUT->header(); - echo $OUTPUT->heading(get_string('assignroles', 'role')); - $mform->display(); - echo $OUTPUT->footer(); - die; + $actiontaken = true; + break; case 'removemember': - $group = required_param('group', PARAM_INT); - $user = required_param('user', PARAM_INT); - if (!$managegroups) { - break; - } - if (!isset($allgroups[$group])) { - break; - } - $group = $allgroups[$group]; - $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST); - - if ($confirm and confirm_sesskey()) { - groups_remove_member($group, $user); - redirect($PAGE->url); - + $groupid = required_param('group', PARAM_INT); + $userid = required_param('user', PARAM_INT); + $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST); + if ($confirm && $manager->remove_user_from_group($user, $groupid)) { + redirect($pageurl); } else { - $yesurl = new moodle_url($PAGE->url, array('action'=>'removemember', 'group'=>$group->id, 'user'=>$user->id, 'confirm'=>1, 'sesskey'=>sesskey())); + $group = $manager->get_group($groupid); + if (!$group) { + break; + } + $yesurl = new moodle_url($pageurl, array('action'=>'removemember', 'group'=>$groupid, 'user'=>$userid, 'confirm'=>1, 'sesskey'=>sesskey())); $message = get_string('removefromgroupconfirm', 'group', array('user'=>fullname($user, true), 'group'=>$group->name)); - $PAGE->set_title(get_string('removefromgroup', 'group', $group->name)); - echo $OUTPUT->header(); - echo $OUTPUT->heading(get_string('removefromgroup', 'group', $group->name)); - echo $OUTPUT->confirm($message, $yesurl, $PAGE->url); - echo $OUTPUT->footer(); - die; + $pagetitle = get_string('removefromgroup', 'group', $group->name); + $pagecontent = $OUTPUT->confirm($message, $yesurl, $pageurl); } + $actiontaken = true; break; case 'addmember': - $user = required_param('user', PARAM_INT); - $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST); - - if (!$managegroups) { - break; - } - if (!is_enrolled($context, $user)) { - break; // no roles without enrolments here in this script - } - - $mform = new enrol_users_addmember_form(NULL, array('user'=>$user, 'course'=>$course, 'allgroups'=>$allgroups)); - - if ($mform->is_cancelled()) { - redirect($PAGE->url); - - } else if ($data = $mform->get_data()) { - if ($data->groupid) { - groups_add_member($data->groupid, $user->id); - } - redirect($PAGE->url); + $userid = required_param('user', PARAM_INT); + $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST); + + $mform = new enrol_users_addmember_form(NULL, array('user'=>$user, 'course'=>$course, 'allgroups'=>$manager->get_all_groups())); + $mform->set_data($pageurl->params()); + $data = $mform->get_data(); + if ($mform->is_cancelled() || ($data && $manager->add_user_to_group($user, $data->groupid))) { + redirect($pageurl); + } else { + $pagetitle = get_string('addgroup', 'group'); } - - $PAGE->set_title(get_string('addgroup', 'group')); - echo $OUTPUT->header(); - echo $OUTPUT->heading(get_string('addgroup', 'group')); - $mform->display(); - echo $OUTPUT->footer(); - die; + $actiontaken = true; + break; case 'edit': $ue = required_param('ue', PARAM_INT); if (!$ue = $DB->get_record('user_enrolments', array('id'=>$ue))) { + $actiontaken = false; break; } $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST); - if (!isset($instances[$ue->enrolid])) { - break; - } - $instance = $instances[$ue->enrolid]; - $plugin = $plugins[$instance->enrol]; - if (!$plugin->allow_unenrol($instance) or !has_capability("enrol/$instance->enrol:unenrol", $context)) { - break; - } $mform = new enrol_users_edit_form(NULL, array('user'=>$user, 'course'=>$course, 'ue'=>$ue)); - - if ($mform->is_cancelled()) { - redirect($PAGE->url); - - } else if ($data = $mform->get_data()) { - if (!isset($data->status)) { - $status = $ue->status; - } - $plugin->update_user_enrol($instance, $ue->userid, $data->status, $data->timestart, $data->timeend); - redirect($PAGE->url); + $mform->set_data($pageurl->params()); + $data = $mform->get_data(); + if ($mform->is_cancelled() || ($data && $manager->edit_enrolment($ue, $data))) { + redirect($pageurl); + } else { + $pagetitle = fullname($user); } - - $PAGE->set_title(fullname($user)); - echo $OUTPUT->header(); - echo $OUTPUT->heading(fullname($user)); - $mform->display(); - echo $OUTPUT->footer(); - die; - } -} - - -echo $OUTPUT->header(); -echo $OUTPUT->heading(get_string('enrolledusers', 'enrol')); -$PAGE->set_title(get_string('enrolledusers', 'enrol')); - -notify('NOTICE TO TESTERS: This interface will shortly be replaced with a new one.'); // TODO FIXME REMOVE THIS - -if ($ifilter) { - $instancessql = " = :ifilter"; - $params = array('ifilter'=>$ifilter); -} else { - if ($instances) { - list($instancessql, $params) = $DB->get_in_or_equal(array_keys($instances), SQL_PARAMS_NAMED); - } else { - // no enabled instances, oops, we should probably say something - $instancessql = "= :never"; - $params = array('never'=>-1); - } -} - -$sqltotal = "SELECT COUNT(DISTINCT u.id) - FROM {user} u - JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql) - JOIN {enrol} e ON (e.id = ue.enrolid)"; -$totalusers = $DB->count_records_sql($sqltotal, $params); - -$ufields = user_picture::fields('u'); -$sql = "SELECT DISTINCT $ufields, ul.timeaccess AS lastseen - FROM {user} u - JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql) - JOIN {enrol} e ON (e.id = ue.enrolid) - LEFT JOIN {user_lastaccess} ul ON (ul.courseid = e.courseid AND ul.userid = u.id)"; -if ($sort === 'firstname') { - $sql .= " ORDER BY u.firstname $dir, u.lastname $dir"; -} else if ($sort === 'lastname') { - $sql .= " ORDER BY u.lastname $dir, u.firstname $dir"; -} else if ($sort === 'email') { - $sql .= " ORDER BY u.email $dir, u.lastname $dir, u.firstname $dir"; -} else if ($sort === 'lastseen') { - $sql .= " ORDER BY ul.timeaccess $dir, u.lastname $dir, u.firstname $dir"; -} - -$pagingbar = new paging_bar($totalusers, $page, $perpage, $PAGE->url, 'page'); - -$users = $DB->get_records_sql($sql, $params, $page*$perpage, $perpage); - -$strfirstname = get_string('firstname'); -$strlastname = get_string('lastname'); -$stremail = get_string('email'); -$strlastseen = get_string('lastaccess'); - -if ($dir === 'ASC') { - $diricon = html_writer::empty_tag('img', array('alt'=>'', 'src'=>$OUTPUT->pix_url('t/down'))); - $newdir = 'DESC'; -} else { - $diricon = html_writer::empty_tag('img', array('alt'=>'', 'src'=>$OUTPUT->pix_url('t/up'))); - $newdir = 'ASC'; -} - -$table = new html_table(); -$table->head = array(); -if ($sort === 'firstname') { - $h = html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $strfirstname); - $h .= " $diricon / "; - $h .= html_writer::link(new moodle_url($PAGE->url, array('sort'=>'lastname')), $strlastname); -} else if ($sort === 'lastname') { - $newdir = ($dir === 'ASC') ? 'DESC' : 'ASC'; - $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'firstname')), $strfirstname); - $h .= " / "; - $h .= html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $strlastname); - $h .= " $diricon"; -} else { - $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'firstname')), $strfirstname); - $h .= " / "; - $h .= html_writer::link(new moodle_url($PAGE->url, array('sort'=>'lastname')), $strlastname); -} -$table->head[] = $h; -if ($sort === 'email') { - $h = html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $stremail); - $h .= " $diricon"; -} else { - $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'email')), $stremail); -} -$table->head[] = $h; -if ($sort === 'lastseen') { - $h = html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $strlastseen); - $h .= " $diricon"; -} else { - $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'lastseen')), $strlastseen); -} -$table->head[] = $h; -$table->head[] = get_string('roles', 'role'); -$table->head[] = get_string('groups', 'group'); -$table->head[] = get_string('enrolmentinstances', 'enrol'); - -$table->align = array('left', 'left', 'left', 'left', 'left', 'left'); -$table->width = "95%"; -foreach ($users as $user) { - $picture = $OUTPUT->user_picture($user, array('courseid'=>$course->id)); - - if ($user->lastseen) { - $strlastaccess = userdate($user->lastseen); - } else { - $strlastaccess = get_string('never'); + $actiontaken = true; + break; } - $fullname = fullname($user, true); - // get list of roles - $roles = array(); - $ras = get_user_roles($context, $user->id, true, 'c.contextlevel DESC, r.sortorder ASC'); - foreach ($ras as $ra) { - if ($ra->contextid != $context->id) { - if (!isset($roles[$ra->roleid])) { - $roles[$ra->roleid] = null; - } - // higher ras, course always takes precedence - continue; - } - if (isset($roles[$ra->roleid]) and $roles[$ra->roleid] === false) { - continue; + if ($actiontaken) { + if (empty($pageheading)) { + $pageheading = $pagetitle; } - $roles[$ra->roleid] = ($ra->itemid == 0 and $ra->component === ''); - } - foreach ($roles as $rid=>$unassignable) { - if ($unassignable and isset($assignable[$rid])) { - $icon = html_writer::empty_tag('img', array('alt'=>get_string('unassignarole', 'role', $allroles[$rid]->localname), 'src'=>$OUTPUT->pix_url('t/delete'))); - $url = new moodle_url($PAGE->url, array('action'=>'unassign', 'role'=>$rid, 'user'=>$user->id)); - $roles[$rid] = $allroles[$rid]->localname . html_writer::link($url, $icon); - } else { - $roles[$rid] = $allroles[$rid]->localname; - } - } - $addrole = ''; - if ($assignable) { - foreach ($assignable as $rid=>$unused) { - if (!isset($roles[$rid])) { - //candidate for role assignment - $icon = html_writer::empty_tag('img', array('alt'=>get_string('assignroles', 'role'), 'src'=>$OUTPUT->pix_url('t/add'))); - $url = new moodle_url($PAGE->url, array('action'=>'assign', 'user'=>$user->id)); - $addrole .= html_writer::link($url, $icon); - break; - } - } - } - $roles = implode(', ', $roles); - if ($addrole) { - $roles = $roles . '
'.$addrole.'
'; - } - - $groups = array(); - $usergroups = groups_get_all_groups($course->id, $user->id, 0, 'g.id'); - foreach($usergroups as $gid=>$unused) { - $group = $allgroups[$gid]; - if ($managegroups) { - $icon = html_writer::empty_tag('img', array('alt'=>get_string('removefromgroup', 'group', $group->name), 'src'=>$OUTPUT->pix_url('t/delete'))); - $url = new moodle_url($PAGE->url, array('action'=>'removemember', 'group'=>$gid, 'user'=>$user->id)); - $groups[] = $group->name . html_writer::link($url, $icon); + $PAGE->set_title($pagetitle); + $PAGE->set_heading($pageheading); + echo $OUTPUT->header(); + echo $OUTPUT->heading(fullname($user)); + if (!is_null($mform)) { + $mform->display(); } else { - $groups[] = $group->name; - } - } - $groups = implode(', ', $groups); - if ($managegroups and (count($usergroups) < count($allgroups))) { - $icon = html_writer::empty_tag('img', array('alt'=>get_string('addgroup', 'group'), 'src'=>$OUTPUT->pix_url('t/add'))); - $url = new moodle_url($PAGE->url, array('action'=>'addmember', 'user'=>$user->id)); - $groups .= '
'.html_writer::link($url, $icon).'
'; - } - - - // get list of enrol instances - $now = time(); - $edits = array(); - $params['userid'] = $user->id; - $ues = $DB->get_records_select('user_enrolments', "enrolid $instancessql AND userid = :userid", $params); - foreach ($ues as $ue) { - $instance = $instances[$ue->enrolid]; - $plugin = $plugins[$instance->enrol]; - - $edit = $inames[$instance->id]; - - $dimmed = false; - if ($ue->timestart and $ue->timeend) { - $edit .= ' ('.get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend))).')'; - $dimmed = ($now < $ue->timestart and $now > $ue->timeend); - } else if ($ue->timestart) { - $edit .= ' ('.get_string('periodstart', 'enrol', userdate($ue->timestart)).')'; - $dimmed = ($now < $ue->timestart); - } else if ($ue->timeend) { - $edit .= ' ('.get_string('periodend', 'enrol', userdate($ue->timeend)).')'; - $dimmed = ($now > $ue->timeend); - } - - if ($dimmed or $ue->status != ENROL_USER_ACTIVE) { - $edit = html_writer::tag('span', $edit, array('class'=>'dimmed_text')); - } - - if ($plugin->allow_unenrol($instance) and has_capability("enrol/$instance->enrol:unenrol", $context)) { - $icon = html_writer::empty_tag('img', array('alt'=>get_string('unenrol', 'enrol'), 'src'=>$OUTPUT->pix_url('t/delete'))); - $url = new moodle_url($PAGE->url, array('action'=>'unenrol', 'ue'=>$ue->id)); - $edit .= html_writer::link($url, $icon); - } - - if ($plugin->allow_manage($instance) and has_capability("enrol/$instance->enrol:manage", $context)) { - $icon = html_writer::empty_tag('img', array('alt'=>get_string('edit'), 'src'=>$OUTPUT->pix_url('t/edit'))); - $url = new moodle_url($PAGE->url, array('action'=>'edit', 'ue'=>$ue->id)); - $edit .= html_writer::link($url, $icon); + echo $pagecontent; } - - $edits[] = $edit; + echo $OUTPUT->footer(); + exit; } - $edits = implode('
', $edits); - - $table->data[] = array("$picture wwwroot/user/view.php?id=$user->id&course=$course->id\">$fullname", $user->email, $strlastaccess, $roles, $groups, $edits); } -$ifilters = new single_select($PAGE->url, 'ifilter', array(0=>get_string('all')) + $inames, $ifilter, array()); -$ifilters->set_label(get_string('enrolmentinstances', 'enrol')); -echo $OUTPUT->render($ifilters); -echo $OUTPUT->render($pagingbar); -echo html_writer::table($table); -echo $OUTPUT->render($pagingbar); +$fields = array( + 'userdetails' => array ( + 'picture' => false, + 'firstname' => get_string('firstname'), + 'lastname' => get_string('lastname'), + 'email' => get_string('email') + ), + 'lastseen' => get_string('lastaccess'), + 'role' => get_string('roles', 'role'), + 'group' => get_string('groups', 'group'), + 'enrol' => get_string('enrolmentinstances', 'enrol') +); +$table->set_fields($fields); + +$renderer = $PAGE->get_renderer('core_enrol'); +$canassign = has_capability('moodle/role:assign', $manager->get_context()); +$users = $manager->get_users_for_display($renderer, $pageurl, $table->sort, $table->sortdirection, $table->page, $table->perpage); +foreach ($users as $userid=>&$user) { + $user['picture'] = $OUTPUT->render($user['picture']); + $user['role'] = $renderer->user_roles_and_actions($userid, $user['roles'], $manager->get_assignable_roles(), $canassign, $pageurl); + $user['group'] = $renderer->user_groups_and_actions($userid, $user['groups'], $manager->get_all_groups(), has_capability('moodle/course:managegroups', $manager->get_context()), $pageurl); + $user['enrol'] = $renderer->user_enrolments_and_actions($userid, $user['enrolments'], $pageurl); +} +$table->set_users($users); -// print enrol link or selection -$links = array(); -foreach($instances as $instance) { - $plugin = $plugins[$instance->enrol]; - if ($link = $plugin->get_manual_enrol_link($instance)) { - $links[$instance->id] = $link; - } -} -if (count($links) == 1) { - $link = reset($links); - echo $OUTPUT->single_button($link, get_string('enrolusers', 'enrol_manual'), 'get'); - -} else if (count($links) > 1) { - $options = array(); - foreach ($links as $i=>$link) { - $options[$link->out(false)] = $inames[$i]; - } - echo $OUTPUT->url_select($options, '', array(''=>get_string('enrolusers', 'enrol_manual').'...')); -} +$PAGE->set_title(get_string('enrolledusers', 'enrol')); +$PAGE->set_heading($PAGE->course->fullname); +echo $OUTPUT->header(); +echo $OUTPUT->heading(get_string('enrolledusers', 'enrol')); +echo $renderer->render($table); echo $OUTPUT->footer(); - - diff --git a/enrol/users_forms.php b/enrol/users_forms.php index 98d82444ce8..9d35df00bf5 100644 --- a/enrol/users_forms.php +++ b/enrol/users_forms.php @@ -30,7 +30,7 @@ require_once("$CFG->libdir/formslib.php"); class enrol_users_assign_form extends moodleform { function definition() { - global $CFG, $DB, $PAGE; + global $CFG, $DB; $mform = $this->_form; @@ -75,14 +75,13 @@ class enrol_users_assign_form extends moodleform { $this->add_action_buttons(); - $this->set_data($PAGE->url->params()); $this->set_data(array('action'=>'assign', 'user'=>$user->id)); } } class enrol_users_addmember_form extends moodleform { function definition() { - global $CFG, $DB, $PAGE; + global $CFG, $DB; $mform = $this->_form; @@ -130,14 +129,13 @@ class enrol_users_addmember_form extends moodleform { $this->add_action_buttons(); - $this->set_data($PAGE->url->params()); $this->set_data(array('action'=>'addmember', 'user'=>$user->id)); } } class enrol_users_edit_form extends moodleform { function definition() { - global $CFG, $DB, $PAGE; + global $CFG, $DB; $mform = $this->_form; @@ -184,7 +182,6 @@ class enrol_users_edit_form extends moodleform { $this->add_action_buttons(); - $this->set_data($PAGE->url->params()); $this->set_data(array('action'=>'edit', 'ue'=>$ue->id, 'status'=>$ue->status, 'timestart'=>$ue->timestart, 'timeend'=>$ue->timeend)); } diff --git a/enrol/yui/enrolmentmanager/assets/skins/sam/enrolmentmanager.css b/enrol/yui/enrolmentmanager/assets/skins/sam/enrolmentmanager.css new file mode 100644 index 00000000000..7147342ab41 --- /dev/null +++ b/enrol/yui/enrolmentmanager/assets/skins/sam/enrolmentmanager.css @@ -0,0 +1,71 @@ +/************************************** + +Structure of the user enroller panel + +.user-enroller-panel(.visible) + .uep-wrap + .uep-header + .uep-content + .uep-ajax-content + .uep-search-results + .totalusers + .users + .user.clearfix(.odd|.even)(.enrolled) + .count + .picture + .details + .fullname + .email + .options + .enrol + .uep-more-results + .uep-loading-lightbox(.hidden) + .loading-icon + .uep-footer + .uep-search + input + .uep-searchoptions + .collapsibleheading + .collapsiblearea(.hidden) + .uep-enrolment-option + .role + .startdate + .duration + +**************************************/ + +.user-enroller-panel {width:400px;background-color:#666;position:absolute;top:10%;left:10%;border:1px solid #666;border-width:0 5px 5px 0;} +.user-enroller-panel.hidden {display:none;} +.user-enroller-panel .uep-wrap {margin-top:-5px;margin-left:-5px;background-color:#FFF;border:1px solid #999;height:inherit;} + +.user-enroller-panel .uep-header {background-color:#eee;padding:1px;} +.user-enroller-panel .uep-header h2 {margin:3px 1em 0.5em 1em;font-size:1em;} +.user-enroller-panel .uep-header .close {width:25px;height:15px;position:absolute;top:2px;right:1em;cursor:pointer;background:url("sprite.png") no-repeat scroll 0 0 transparent;} + +.user-enroller-panel .uep-content {text-align:center;position:relative;width:100%;border-top:1px solid #999;border-bottom:1px solid #999;} +.user-enroller-panel .uep-ajax-content {height:375px;overflow:auto;} +.user-enroller-panel .uep-search-results .totalusers {background-color:#eee;padding:5px;border-bottom:1px solid #BBB;font-size:7pt;font-weight: bold;} +.user-enroller-panel .uep-search-results .user {width:100%;text-align:left;font-size:9pt;border-bottom:1px solid #ddd;border-top:1px solid #eee;} +.user-enroller-panel .uep-search-results .user.odd {border-bottom:1px solid #ddd;border-top:1px solid #eee;background-color:#f9f9f9;} +.user-enroller-panel .uep-search-results .user .count {width:20px;float:left;font-size:7pt;line-height:41px;border-right:1px solid #ddd;background-color:#EEE;text-align:right;padding:2px;} +.user-enroller-panel .uep-search-results .user .picture {width:45px;float:left;margin:3px;} +.user-enroller-panel .uep-search-results .user .details {width:250px;float:left;margin:3px;} +.user-enroller-panel .uep-search-results .user .options {padding-right:7px;font-size:8pt;margin:3px;} +.user-enroller-panel .uep-search-results .user .options .enrol {margin:3px;float:right;border:1px outset #ddd;background-color:#EEE;padding:3px;-moz-border-radius:3px;cursor:pointer;} +.user-enroller-panel .uep-search-results .user.enrolled .count {width:40px;color:#eee;} +.user-enroller-panel .uep-search-results .uep-more-results {background-color:#eee;padding:5px;border-top:1px solid #BBB;} + +.user-enroller-panel .uep-loading-lightbox {position:absolute;width:100%;height:100%;top:0;left:0;background-color:#FFF;min-width:50px;min-height:50px;} +.user-enroller-panel .uep-loading-lightbox.hidden {display:none;} +.user-enroller-panel .uep-loading-lightbox .loading-icon {margin:auto;vertical-align:middle;margin-top:125px;} + +.user-enroller-panel .uep-footer {padding:3px;background-color:#ddd;} +.user-enroller-panel .uep-search {margin:3px;} +.user-enroller-panel .uep-search label {padding-right:8px;} +.user-enroller-panel .uep-search input {width:70%;} +.user-enroller-panel .uep-searchoptions {margin:3px;cursor:pointer;} +.user-enroller-panel .uep-searchoptions select {margin-left:1em;} +.user-enroller-panel .collapsibleheading img {margin-right:8px;} +.user-enroller-panel .collapsiblearea {border:1px solid #bbb;background-color:#f6f6f6;} +.user-enroller-panel .collapsiblearea.hidden {display:none;} +.user-enroller-panel .collapsiblearea .uep-enrolment-option {margin:5px 1em;} diff --git a/enrol/yui/enrolmentmanager/assets/skins/sam/sprite.png b/enrol/yui/enrolmentmanager/assets/skins/sam/sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..3716fc0b95fc1f9f585dd316d99358ff95d4d164 GIT binary patch literal 1002 zcmVP000jN0{{R3Cb*Q>00001b5ch_0Itp) z=>Px&08mU+Mc3Hc!NI}){{C%kZT$TF`}_O#_4WGt`uF$u+Ip;Ol~;p6cC z?eFjU`uped|Jv#Q-rwNm=H~hN`G0?Z;Naong(Ft+uYpU(9zQ8 z=<3(k*t*#N?CkBn!NT$K^7Qod#Kp$l-QTmdx9I5V`TF`WR<$ltu=MryKy202)z(05 z);VFsxVyc{%FFfk_BUU`tgo;=XU;oi%Q<7n?CtIE@9#is)bQ}}@bK{P@$vET@$&NY zC`_g+POI(h@8#v@_V)M8&d~NWG~ss}ot>TSi5v0KSST@*rOW@}dJ?g*vH85b=&L)H zs>908>F1<9>cA=Ly*KH)CD*ek_zMejb93v$HTmea=(0L)imdfVN0yeB>9;ue6&3T& zJm{wz_#`CrQb!XGOXi$E)Cd7dNlE2s1fg>dE;pR@%S`679^vQj_+eh?l0xR173Y2z z=H}+rF#+b3J0BbPgpe zhv?|&_f=K)YHGBTNc6~};8_CBu}p-A!S}>~;$aQ-vQ>V6tgW%cQe(RAk14H&A|E7o z_27&=QMUYXcb=os<;qQ@tK0kP-{y8M;qL$6$#wnj;_Fsd?TaDvqdV}HEY>_A*~W|Z zdV1k>5qETx&@#10r382@1hjKs(kvjGXVVoaH0W*xSF zY&y)v7&1UX9ey25P=>;M1&07*qoM6N<$f^5H2h5!Hn literal 0 HcmV?d00001 diff --git a/enrol/yui/enrolmentmanager/enrolmentmanager.js b/enrol/yui/enrolmentmanager/enrolmentmanager.js new file mode 100644 index 00000000000..936f79d997f --- /dev/null +++ b/enrol/yui/enrolmentmanager/enrolmentmanager.js @@ -0,0 +1,493 @@ +YUI.add('moodle-enrol-enrolmentmanager', function(Y) { + + var UEP = { + NAME : 'Enrolment Manager', + /** Properties **/ + BASE : 'base', + SEARCH : 'search', + PARAMS : 'params', + URL : 'url', + AJAXURL : 'ajaxurl', + MULTIPLE : 'multiple', + PAGE : 'page', + COURSEID : 'courseid', + USERS : 'users', + USERCOUNT : 'userCount', + REQUIREREFRESH : 'requiresRefresh', + LASTSEARCH : 'lastPreSearchValue', + INSTANCES : 'instances', + OPTIONSTARTDATE : 'optionsStartDate', + DEFAULTROLE : 'defaultRole', + DEFAULTSTARTDATE : 'defaultStartDate', + DEFAULTDURATION : 'defaultDuration', + ASSIGNABLEROLES : 'assignableRoles' + }, + /** CSS classes for nodes in structure **/ + CSS = { + PANEL : 'user-enroller-panel', + WRAP : 'uep-wrap', + HEADER : 'uep-header', + CONTENT : 'uep-content', + AJAXCONTENT : 'uep-ajax-content', + SEARCHRESULTS : 'uep-search-results', + TOTALUSERS : 'totalusers', + USERS : 'users', + USER : 'user', + MORERESULTS : 'uep-more-results', + LIGHTBOX : 'uep-loading-lightbox', + LOADINGICON : 'loading-icon', + FOOTER : 'uep-footer', + ENROL : 'enrol', + ENROLLED : 'enrolled', + COUNT : 'count', + PICTURE : 'picture', + DETAILS : 'details', + FULLNAME : 'fullname', + EMAIL : 'email', + OPTIONS : 'options', + ODD : 'odd', + EVEN : 'even', + HIDDEN : 'hidden', + SEARCHOPTIONS : 'uep-searchoptions', + COLLAPSIBLEHEADING : 'collapsibleheading', + COLLAPSIBLEAREA : 'collapsiblearea', + SEARCHOPTION : 'uep-enrolment-option', + ROLE : 'role', + STARTDATE : 'startdate', + DURATION : 'duration', + ACTIVE : 'active', + SEARCH : 'uep-search', + CLOSE : 'close' + }; + + var USERENROLLER = function(config) { + USERENROLLER.superclass.constructor.apply(this, arguments); + }; + Y.extend(USERENROLLER, Y.Base, { + _searchTimeout : null, + _loadingNode : null, + _escCloseEvent : null, + initializer : function(config) { + this.set(UEP.BASE, Y.Node.create('
') + .append(Y.Node.create('
') + .append(Y.Node.create('
') + .append(Y.Node.create('
')) + .append(Y.Node.create('

'+M.str.enrol.enrolusers+'

'))) + .append(Y.Node.create('
') + .append(Y.Node.create('
')) + .append(Y.Node.create('
') + .append(Y.Node.create('loading') + .setAttribute('src', M.util.image_url('i/loading', 'moodle'))) + .setStyle('opacity', 0.5))) + .append(Y.Node.create('
') + .append(Y.Node.create('
') + .append(Y.Node.create('')) + .append(Y.Node.create('
'+M.str.role.assignroles+'
') + .append(Y.Node.create('')) + ) + ) + .append(Y.Node.create('
') + .append(Y.Node.create('
'+M.str.enrol.enrolmentoptions+'
')) + .append(Y.Node.create('
') + .append(Y.Node.create('
'+M.str.moodle.startingfrom+'
') + .append(Y.Node.create(''))) + .append(Y.Node.create('
'+M.str.enrol.enrolperiod+'
') + .append(Y.Node.create(''))) + ) + ) + ) + ) + ); + + this.set(UEP.SEARCH, this.get(UEP.BASE).one('#enrolusersearch')); + Y.all('.enrolusersbutton input').each(function(node){ + if (node.getAttribute('type', 'submit')) { + node.on('click', this.show, this); + } + }, this); + this.get(UEP.BASE).one('.'+CSS.HEADER+' .'+CSS.CLOSE).on('click', this.hide, this); + this._loadingNode = this.get(UEP.BASE).one('.'+CSS.CONTENT+' .'+CSS.LIGHTBOX); + var params = this.get(UEP.PARAMS); + params['id'] = this.get(UEP.COURSEID); + this.set(UEP.PARAMS, params); + + Y.on('key', this.preSearch, this.get(UEP.SEARCH), 'down:13', this); + + Y.one(document.body).append(this.get(UEP.BASE)); + + var base = this.get(UEP.BASE); + base.plug(Y.Plugin.Drag); + base.dd.addHandle('.'+CSS.HEADER+' h2'); + base.one('.'+CSS.HEADER+' h2').setStyle('cursor', 'move'); + + + this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url('t/collapsed', 'moodle')); + this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).on('click', function(){ + this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).toggleClass(CSS.ACTIVE); + this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEAREA).toggleClass(CSS.HIDDEN); + if (this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEAREA).hasClass(CSS.HIDDEN)) { + this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url('t/collapsed', 'moodle')); + } else { + this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url('t/expanded', 'moodle')); + } + }, this); + + this.populateAssignableRoles(); + this.populateStartDates(); + this.populateDuration(); + }, + populateAssignableRoles : function() { + this.on('assignablerolesloaded', function(){ + var roles = this.get(UEP.ASSIGNABLEROLES); + var s = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.ROLE+' select'); + var v = this.get(UEP.DEFAULTROLE); + var index = 0, count = 0; + for (var i in roles) { + count++; + var option = Y.Node.create(''); + if (i == v) { + index = count; + } + s.append(option); + } + s.set('selectedIndex', index); + }, this); + this.getAssignableRoles(); + }, + populateStartDates : function() { + var select = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.STARTDATE+' select'); + var defaultvalue = this.get(UEP.DEFAULTSTARTDATE); + var options = this.get(UEP.OPTIONSTARTDATE); + var index = 0, count = 0; + for (var i in options) { + count++; + var option = Y.Node.create(''); + if (i == defaultvalue) { + index = count; + } + select.append(option); + } + select.set('selectedIndex', index); + }, + populateDuration : function() { + var select = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.DURATION+' select'); + var defaultvalue = this.get(UEP.DEFAULTDURATION); + var index = 0, count = 0; + for (var i = 1; i <= 365; i++) { + count++; + var option = Y.Node.create(''); + if (i == defaultvalue) { + index = count; + } + select.append(option); + } + select.set('selectedIndex', index); + }, + getAssignableRoles : function(){ + Y.io(M.cfg.wwwroot+'/enrol/ajax.php', { + method:'POST', + data:'id='+this.get(UEP.COURSEID)+'&action=getassignable&sesskey='+M.cfg.sesskey, + on: { + complete: function(tid, outcome, args) { + try { + var roles = Y.JSON.parse(outcome.responseText); + this.set(UEP.ASSIGNABLEROLES, roles.response); + } catch (e) { + Y.fail(UEP.NAME+': Failed to load assignable roles'); + } + this.getAssignableRoles = function() { + this.fire('assignablerolesloaded'); + } + this.getAssignableRoles(); + } + }, + context:this + }); + }, + preSearch : function(e) { + this.search(null, false); + /* + var value = this.get(UEP.SEARCH).get('value'); + if (value.length < 3 || value == this.get(UEP.LASTSEARCH)) { + return; + } + this.set(UEP.LASTSEARCH, value); + if (this._searchTimeout) { + clearTimeout(this._searchTimeout); + this._searchTimeout = null; + } + var self = this; + this._searchTimeout = setTimeout(function(){ + self._searchTimeout = null; + self.search(null, false); + }, 300); + */ + }, + show : function(e) { + e.preventDefault(); + e.halt(); + + var base = this.get(UEP.BASE); + base.removeClass(CSS.HIDDEN); + var x = (base.get('winWidth') - 400)/2; + var y = (parseInt(base.get('winHeight'))-base.get('offsetHeight'))/2 + parseInt(base.get('docScrollY')); + if (y < parseInt(base.get('winHeight'))*0.1) { + y = parseInt(base.get('winHeight'))*0.1; + } + base.setXY([x,y]); + + if (this.get(UEP.USERS)===null) { + this.search(e, false); + } + + this._escCloseEvent = Y.on('key', this.hide, document.body, 'down:27', this); + }, + hide : function(e) { + if (this._escCloseEvent) { + this._escCloseEvent.detach(); + this._escCloseEvent = null; + } + this.get(UEP.BASE).addClass(CSS.HIDDEN); + if (this.get(UEP.REQUIREREFRESH)) { + window.location = this.get(UEP.URL); + } + }, + search : function(e, append) { + if (e) { + e.halt(); + e.preventDefault(); + } + var on, params; + if (append) { + this.set(UEP.PAGE, this.get(UEP.PAGE)+1); + } else { + this.set(UEP.USERCOUNT, 0); + } + params = this.get(UEP.PARAMS); + params['sesskey'] = M.cfg.sesskey; + params['action'] = 'searchusers'; + params['search'] = this.get(UEP.SEARCH).get('value'); + params['page'] = this.get(UEP.PAGE); + if (this.get(UEP.MULTIPLE)) { + alert('oh no there are multiple'); + } else { + var instance = this.get(UEP.INSTANCES)[0]; + params['enrolid'] = instance.id; + } + Y.io(M.cfg.wwwroot+this.get(UEP.AJAXURL), { + method:'POST', + data:build_querystring(params), + on : { + start : this.displayLoading, + complete: this.processSearchResults, + end : this.removeLoading + }, + context:this, + arguments:{ + append:append, + enrolid:params['enrolid'] + } + }); + }, + displayLoading : function() { + this._loadingNode.removeClass(CSS.HIDDEN); + }, + removeLoading : function() { + this._loadingNode.addClass(CSS.HIDDEN); + }, + processSearchResults : function(tid, outcome, args) { + try { + var result = Y.JSON.parse(outcome.responseText); + } catch (e) { + Y.fail(UEP.NAME+': Failed to parse user search response ['+e.linenum+':'+e.message+']'); + } + if (!result.success) { + this.setContent = M.str.enrol.errajaxsearch; + } + var users; + if (!args.append) { + users = Y.Node.create('
'); + } else { + users = this.get(UEP.BASE).one('.'+CSS.SEARCHRESULTS+' .'+CSS.USERS); + } + var count = this.get(UEP.USERCOUNT); + for (var i in result.response.users) { + count++; + var user = result.response.users[i]; + users.append(Y.Node.create('
') + .addClass((i%2)?CSS.ODD:CSS.EVEN) + .append(Y.Node.create('
'+count+'
')) + .append(Y.Node.create('
') + .append(Y.Node.create(user.picture))) + .append(Y.Node.create('
') + .append(Y.Node.create('
'+user.fullname+'
')) + .append(Y.Node.create('
'+user.email+'
'))) + .append(Y.Node.create('
') + .append(Y.Node.create('
'+M.str.enrol.enrol+'
'))) + ); + } + this.set(UEP.USERCOUNT, count); + if (!args.append) { + var usersstr = (result.response.totalusers == '1')?M.str.enrol.ajaxoneuserfound:M.str.enrol.ajaxxusersfound.replace(/\[users\]/, result.response.totalusers); + var content = Y.Node.create('
') + .append(Y.Node.create('
'+usersstr+'
')) + .append(users); + if (result.response.totalusers > (this.get(UEP.PAGE)+1)*25) { + var fetchmore = Y.Node.create(''); + fetchmore.on('click', this.search, this, true); + content.append(fetchmore) + } + this.setContent(content); + Y.delegate("click", this.enrolUser, users, '.'+CSS.USER+' .'+CSS.ENROL, this, args); + } else { + if (result.response.totalusers <= (this.get(UEP.PAGE)+1)*25) { + this.get(UEP.BASE).one('.'+CSS.MORERESULTS).remove(); + } + } + }, + enrolUser : function(e, args) { + var user = e.currentTarget.ancestor('.'+CSS.USER); + var params = []; + params['id'] = this.get(UEP.COURSEID); + params['userid'] = user.getAttribute("rel"); + params['enrolid'] = args.enrolid; + params['sesskey'] = M.cfg.sesskey; + params['action'] = 'enrol'; + params['role'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.ROLE+' select').get('value'); + params['startdate'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.STARTDATE+' select').get('value'); + params['duration'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.DURATION+' select').get('value'); + Y.io(M.cfg.wwwroot+this.get(UEP.AJAXURL), { + method:'POST', + data:build_querystring(params), + on: { + start : this.displayLoading, + complete : function(tid, outcome, args) { + try { + var result = Y.JSON.parse(outcome.responseText); + } catch (e) { + Y.fail(UEP.NAME+': Failed to parse user search response ['+e.linenum+':'+e.message+']'); + } + if (result.success) { + args.userNode.addClass(CSS.ENROLLED); + args.userNode.one('.'+CSS.ENROL).remove(); + this.set(UEP.REQUIREREFRESH, true); + } else { + alert(M.str.enrol.errajaxfailedenrol); + } + }, + end : this.removeLoading + }, + context:this, + arguments:{ + params : params, + userNode : user + } + }); + + }, + setContent: function(content) { + this.get(UEP.BASE).one('.'+CSS.CONTENT+' .'+CSS.AJAXCONTENT).setContent(content); + } + }, { + NAME : UEP.NAME, + ATTRS : { + url : { + validator : Y.Lang.isString + }, + ajaxurl : { + validator : Y.Lang.isString + }, + base : { + setter : function(node) { + var n = Y.one(node); + if (!n) { + Y.fail(UEP.NAME+': invalid base node set'); + } + return n; + } + }, + users : { + validator : Y.Lang.isArray, + value : null + }, + courseid : { + value : null + }, + params : { + validator : Y.Lang.isArray, + value : [] + }, + instances : { + validator : Y.Lang.isArray, + setter : function(instances) { + var i,ia = [], count=0; + for (i in instances) { + ia.push(instances[i]); + count++; + } + this.set(UEP.MULTIPLE, (count>1)); + } + }, + multiple : { + validator : Y.Lang.isBool, + value : false + }, + page : { + validator : Y.Lang.isNumber, + value : 0 + }, + userCount : { + value : 0, + validator : Y.Lang.isNumber + }, + requiresRefresh : { + value : false, + validator : Y.Lang.isBool + }, + search : { + setter : function(node) { + var n = Y.one(node); + if (!n) { + Y.fail(UEP.NAME+': invalid search node set'); + } + return n; + } + }, + lastPreSearchValue : { + value : '', + validator : Y.Lang.isString + }, + strings : { + value : {}, + validator : Y.Lang.isObject + }, + defaultRole : { + value : 0, + validator : Y.Lang.isNumber + }, + defaultStartDate : { + value : 2, + validator : Y.Lang.isNumber + }, + defaultDuration : { + value : '' + }, + assignableRoles : { + value : [] + }, + optionsStartDate : { + value : [] + } + } + }); + Y.augment(USERENROLLER, Y.EventTarget); + + + M.enrol = M.enrol || {}; + M.enrol.enrolmentmanager = { + init : function(cfg) { + new USERENROLLER(cfg); + } + } + +}, '@VERSION@', {requires:['base','node', 'overlay', 'io', 'test', 'json-parse', 'event-delegate', 'dd-plugin', 'event-key']}); \ No newline at end of file diff --git a/enrol/yui/rolemanager/assets/skins/sam/rolemanager.css b/enrol/yui/rolemanager/assets/skins/sam/rolemanager.css new file mode 100644 index 00000000000..504323c9de1 --- /dev/null +++ b/enrol/yui/rolemanager/assets/skins/sam/rolemanager.css @@ -0,0 +1,8 @@ +.enrolpanel {display:none;position:absolute;background-color:#666;padding:0 5px;} +.enrolpanel.visible {display:block;} +.enrolpanel .container {position:relative;background-color:#fff;border:1px solid #999;top:-5px;} +.enrolpanel .container .header {border-bottom:1px solid #999;} +.enrolpanel .container .header h2 {font-size:90%;text-align:center;margin:5px;} +.enrolpanel .container .header .close {width:25px;height:15px;position:absolute;top:5px;right:1em;cursor:pointer;background:url("sprite.png") no-repeat scroll 0 0 transparent;} +.enrolpanel .container .content {} +.enrolpanel .container .content input {margin:5px;font-size:10px;} \ No newline at end of file diff --git a/enrol/yui/rolemanager/assets/skins/sam/sprite.png b/enrol/yui/rolemanager/assets/skins/sam/sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..3716fc0b95fc1f9f585dd316d99358ff95d4d164 GIT binary patch literal 1002 zcmVP000jN0{{R3Cb*Q>00001b5ch_0Itp) z=>Px&08mU+Mc3Hc!NI}){{C%kZT$TF`}_O#_4WGt`uF$u+Ip;Ol~;p6cC z?eFjU`uped|Jv#Q-rwNm=H~hN`G0?Z;Naong(Ft+uYpU(9zQ8 z=<3(k*t*#N?CkBn!NT$K^7Qod#Kp$l-QTmdx9I5V`TF`WR<$ltu=MryKy202)z(05 z);VFsxVyc{%FFfk_BUU`tgo;=XU;oi%Q<7n?CtIE@9#is)bQ}}@bK{P@$vET@$&NY zC`_g+POI(h@8#v@_V)M8&d~NWG~ss}ot>TSi5v0KSST@*rOW@}dJ?g*vH85b=&L)H zs>908>F1<9>cA=Ly*KH)CD*ek_zMejb93v$HTmea=(0L)imdfVN0yeB>9;ue6&3T& zJm{wz_#`CrQb!XGOXi$E)Cd7dNlE2s1fg>dE;pR@%S`679^vQj_+eh?l0xR173Y2z z=H}+rF#+b3J0BbPgpe zhv?|&_f=K)YHGBTNc6~};8_CBu}p-A!S}>~;$aQ-vQ>V6tgW%cQe(RAk14H&A|E7o z_27&=QMUYXcb=os<;qQ@tK0kP-{y8M;qL$6$#wnj;_Fsd?TaDvqdV}HEY>_A*~W|Z zdV1k>5qETx&@#10r382@1hjKs(kvjGXVVoaH0W*xSF zY&y)v7&1UX9ey25P=>;M1&07*qoM6N<$f^5H2h5!Hn literal 0 HcmV?d00001 diff --git a/enrol/yui/rolemanager/rolemanager.js b/enrol/yui/rolemanager/rolemanager.js new file mode 100644 index 00000000000..36ab64bd4f7 --- /dev/null +++ b/enrol/yui/rolemanager/rolemanager.js @@ -0,0 +1,389 @@ +YUI.add('moodle-enrol-rolemanager', function(Y) { + + var MOD_NAME = 'Moodle role manager', + MOD_USER = 'Moodle role user', + MOD_PANEL = 'Moodle role assignment panel', + USERIDS = 'userIds', + COURSEID = 'courseId', + USERID = 'userId', + CONTAINER = 'container', + CONTAINERID = 'containerId', + ASSIGNABLEROLES = 'assignableRoles', + ASSIGNROLELINK = 'assignRoleLink', + ASSIGNROLELINKSELECTOR = 'assignRoleLinkSelector', + UNASSIGNROLELINKS = 'unassignRoleLinks', + UNASSIGNROLELINKSSELECTOR = 'unassignRoleLinksSelector', + MANIPULATOR = 'manipulator', + CURRENTROLES = 'currentroles'; + + var ROLE = function(config) { + ROLE.superclass.constructor.apply(this, arguments); + } + ROLE.NAME = MOD_NAME; + ROLE.ATTRS = { + containerId : { + validator: Y.Lang.isString + }, + container : { + setter : function(node) { + var n = Y.one(node); + if (!n) { + Y.fail(MOD_NAME+': invalid container set'); + } + return n; + } + }, + courseId : { + value: 0, + setter : function(courseId) { + if (!(/^\d+$/.test(courseId))) { + Y.fail(MOD_NAME+': Invalid course id specified'); + } + return courseId; + } + }, + userIds : { + validator: Y.Lang.isArray + }, + assignableRoles : { + value : [] + } + } + Y.extend(ROLE, Y.Base, { + users : [], + roleAssignmentPanel : null, + panelsubmitevent : null, + rolesLoadedEvent : null, + escCloseEvent : null, + initializer : function(config) { + var i; + var container = Y.one('#'+this.get(CONTAINERID)); + container.addClass('ajaxactive'); + this.set(CONTAINER, container); + + var userids = this.get(USERIDS); + for (i in userids) { + this.users[userids[i]] = new ROLEUSER({userId:userids[i],manipulator:this}).wire(); + } + }, + addRole : function(e, user) { + e.halt(); + this.rolesLoadedEvent = this.on('assignablerolesloaded', function(){ + this.rolesLoadedEvent.detach(); + var panel = this._getRoleAssignmentPanel(); + this.panelsubmitevent = panel.on('submit', this.addRoleCallback, this); + panel.hide().display(user); + }, this); + this._loadAssignableRoles(); + }, + addRoleCallback : function(e, roleid, userid) { + this.panelsubmitevent.detach(); + var panel = this._getRoleAssignmentPanel(); + Y.io(M.cfg.wwwroot+'/enrol/ajax.php', { + method:'POST', + data:'id='+this.get(COURSEID)+'&action=assign&sesskey='+M.cfg.sesskey+'&roleid='+roleid+'&user='+userid, + on: { + complete: function(tid, outcome, args) { + try { + var o = Y.JSON.parse(outcome.responseText); + if (o.success) { + panel.user.addRoleToDisplay(args.roleid, this.get(ASSIGNABLEROLES)[args.roleid]); + } + } catch (e) { + Y.fail(MOD_PANEL+': Failed to parse role assignment response ['+e.linenum+':'+e.message+']'); + } + panel.hide(); + } + }, + context:this, + arguments:{ + roleid : roleid + } + }); + }, + removeRole : function(e, user, roleid) { + e.halt(); + if (confirm('Are you sure you wish to remove this role from this user?')) { + this.removeRoleCallback(e, user.get(USERID), roleid); + } + }, + removeRoleCallback : function(e, userid, roleid) { + Y.io(M.cfg.wwwroot+'/enrol/ajax.php', { + method:'POST', + data:'id='+this.get(COURSEID)+'&action=unassign&sesskey='+M.cfg.sesskey+'&role='+roleid+'&user='+userid, + on: { + complete: function(tid, outcome, args) { + try { + var o = Y.JSON.parse(outcome.responseText); + if (o.success) { + this.users[userid].removeRoleFromDisplay(args.roleid); + } + } catch (e) { + Y.fail(MOD_PANEL+': Failed to parse role assignment response ['+e.linenum+':'+e.message+']'); + } + } + }, + context:this, + arguments:{ + roleid : roleid + } + }); + }, + _loadAssignableRoles : function() { + var c = this.get(COURSEID); + Y.io(M.cfg.wwwroot+'/enrol/ajax.php', { + method:'POST', + data:'id='+this.get(COURSEID)+'&action=getassignable&sesskey='+M.cfg.sesskey, + on: { + complete: function(tid, outcome, args) { + try { + var roles = Y.JSON.parse(outcome.responseText); + this.set(ASSIGNABLEROLES, roles.response); + } catch (e) { + Y.fail(MOD_NAME+': Failed to load assignable roles'); + } + this._loadAssignableRoles = function() { + this.fire('assignablerolesloaded'); + } + this._loadAssignableRoles(); + } + }, + context:this + }); + }, + _getRoleAssignmentPanel : function() { + if (this.roleAssignmentPanel === null) { + this.roleAssignmentPanel = new ROLEPANEL({manipulator:this}); + } + return this.roleAssignmentPanel; + } + }); + Y.augment(ROLE, Y.EventTarget); + + var ROLEUSER = function(config) { + ROLEUSER.superclass.constructor.apply(this, arguments); + } + ROLEUSER.NAME = MOD_USER; + ROLEUSER.ATTRS = { + userId : { + validator: Y.Lang.isNumber + }, + manipulator : { + validator: Y.Lang.isObject + }, + container : { + setter : function(node) { + var n = Y.one(node); + if (!n) { + Y.fail(MOD_USER+': invalid container set '+node); + } + return n; + } + }, + assignableroles : { + value : [] + }, + currentroles : { + value : [], + validator: Y.Lang.isArray + }, + assignRoleLink : { + setter : function(node) { + if (node===false) { + return node; + } + var n = Y.one(node); + if (!n) { + Y.fail(MOD_NAME+': invalid assign role link given '+node); + } + return n; + }, + value : false + }, + assignRoleLinkSelector : { + value : '.assignrolelink', + validator : Y.Lang.isString + }, + unassignRoleLinks : { + }, + unassignRoleLinksSelector : { + value : '.unassignrolelink', + validator : Y.Lang.isString + } + } + Y.extend(ROLEUSER, Y.Base, { + initializer : function() { + var container = this.get(MANIPULATOR).get(CONTAINER).one('#user_'+this.get(USERID)); + this.set(CONTAINER, container); + var assignrole = container.one(this.get(ASSIGNROLELINKSELECTOR)); + if (assignrole) { + this.set(ASSIGNROLELINK, assignrole.ancestor()); + } + this.set(UNASSIGNROLELINKS , container.all(this.get(UNASSIGNROLELINKSSELECTOR))); + }, + wire : function() { + var container = this.get(MANIPULATOR).get(CONTAINER).one('#user_'+this.get(USERID)); + var arl = this.get(ASSIGNROLELINK); + var uarls = this.get(UNASSIGNROLELINKS); + var m = this.get(MANIPULATOR); + if (arl) { + arl.ancestor().on('click', m.addRole, m, this); + } + var currentroles = []; + if (uarls.size() > 0) { + uarls.each(function(link){ + link.roleId = link.getAttribute('rel'); + link.on('click', m.removeRole, m, this, link.roleId); + currentroles[link.roleId] = true; + }, this); + } + container.all('.role.unchangeable').each(function(node){ + currentroles[node.getAttribute('rel')] = true; + }, this); + + this.set(CURRENTROLES, currentroles); + return this; + }, + _checkIfHasAllRoles : function() { + var roles = this.get(MANIPULATOR).get(ASSIGNABLEROLES); + var current = this.get(CURRENTROLES); + var allroles = true, i = 0; + for (i in roles) { + if (!current[i]) { + allroles = false; + break; + } + } + var link = this.get(ASSIGNROLELINK); + if (allroles) { + this.get(CONTAINER).addClass('hasAllRoles'); + } else { + if (!link) { + var m = this.get(MANIPULATOR); + link = Y.Node.create('
 
'); + link.on('click', m.addRole, m, this); + this.get(CONTAINER).one('.col_role').insert(link, 0); + this.set(ASSIGNROLELINK, link); + } + this.get(CONTAINER).removeClass('hasAllRoles'); + } + }, + addRoleToDisplay : function(roleId, roleTitle) { + var m = this.get(MANIPULATOR); + var container = this.get(CONTAINER); + var role = Y.Node.create('
'+roleTitle+'
'); + var link = role.one('.unassignrolelink'); + link.roleId = roleId; + link.on('click', m.removeRole, m, this, link.roleId); + container.one('.col_role .roles').append(role); + this._toggleCurrentRole(link.roleId, true); + }, + removeRoleFromDisplay : function(roleId) { + var container = this.get(CONTAINER); + container.all('.role_'+roleId).remove(); + this._toggleCurrentRole(roleId, false); + }, + _toggleCurrentRole : function(roleId, hasRole) { + var roles = this.get(CURRENTROLES); + if (hasRole) { + roles[roleId] = true; + } else { + roles[roleId] = false; + } + this.set(CURRENTROLES, roles); + this._checkIfHasAllRoles(); + } + }); + + var ROLEPANEL = function(config) { + ROLEPANEL.superclass.constructor.apply(this, arguments); + } + ROLEPANEL.NAME = MOD_PANEL; + ROLEPANEL.ATTRS = { + elementNode : { + setter : function(node) { + var n = Y.one(node); + if (!n) { + Y.fail(MOD_PANEL+': Invalid element node'); + } + return n; + } + }, + contentNode : { + setter : function(node) { + var n = Y.one(node); + if (!n) { + Y.fail(MOD_PANEL+': Invalid content node'); + } + return n; + } + }, + manipulator : { + validator: Y.Lang.isObject + } + } + Y.extend(ROLEPANEL, Y.Base, { + user : null, + roles : [], + initializer : function() { + var i, m = this.get(MANIPULATOR); + var element = Y.Node.create('

'+M.str.role.assignroles+'

'); + var content = element.one('.content'); + var roles = m.get(ASSIGNABLEROLES); + for (i in roles) { + var button = Y.Node.create(''); + button.on('click', this.submit, this, i); + content.append(button); + } + Y.one(document.body).append(element); + this.set('elementNode', element); + this.set('contentNode', content); + element.one('.header .close').on('click', this.hide, this); + }, + display : function(user) { + var currentroles = user.get(CURRENTROLES); + for (var i in currentroles) { + if (currentroles[i] === true) { + this.get('contentNode').one('#add_assignable_role_'+i).setAttribute('disabled', 'disabled'); + this.roles.push(i); + } + } + this.user = user; + var roles = this.user.get(CONTAINER).one('.col_role .roles'); + var x = roles.getX() + 10; + var y = roles.getY() + this.user.get(CONTAINER).get('offsetHeight') - 10 + Y.one(window).get('scrollTop'); + this.get('elementNode').setXY([x, y]); + this.get('elementNode').addClass('visible'); + this.escCloseEvent = Y.on('key', this.hide, document.body, 'down:27', this); + this.displayed = true; + }, + hide : function() { + if (this._escCloseEvent) { + this._escCloseEvent.detach(); + this._escCloseEvent = null; + } + for (var i in this.roles) { + this.get('contentNode').one('#add_assignable_role_'+this.roles[i]).removeAttribute('disabled'); + } + this.roles = []; + this.user = null; + this.get('elementNode').removeClass('visible'); + this.displayed = false; + return this; + }, + submit : function(e, roleid) { + this.fire('submit', roleid, this.user.get(USERID)); + } + }); + Y.augment(ROLEPANEL, Y.EventTarget); + + M.enrol = M.enrol || {}; + M.enrol.rolemanager = { + instance : null, + init : function(config) { + M.enrol.rolemanager.instance = new ROLE(config); + return M.enrol.rolemanager.instance; + } + } + +}, '@VERSION@', {requires:['base','node','io','json-parse','test']}); \ No newline at end of file diff --git a/lang/en/enrol.php b/lang/en/enrol.php index 4b9e65e5e79..6bdc427f961 100644 --- a/lang/en/enrol.php +++ b/lang/en/enrol.php @@ -26,10 +26,15 @@ $string['actenrolshhdr'] = 'Available course enrolment plugins'; $string['addinstance'] = 'Add method'; +$string['ajaxoneuserfound'] = '1 user found'; +$string['ajaxxusersfound'] = '[users] users found'; +$string['ajaxnext25'] = 'Next 25...'; $string['configenrolplugins'] = 'Please select all required plugins and arrange then in appropriate order.'; $string['defaultenrol'] = 'Add instance to new courses'; $string['defaultenrol_desc'] = 'It is possible to add this plugin to all new courses by default.'; $string['deleteinstanceconfirm'] = 'Do you really want to delete enrol plugin instance "{$a->name}" with {$a->users} enrolled users?'; +$string['durationdays'] = '%d days'; +$string['enrol'] = 'Enrol'; $string['enrolcandidates'] = 'Not enrolled users'; $string['enrolcandidatesmatching'] = 'Matching not enrolled users'; $string['enrolledusers'] = 'Enrolled users'; @@ -39,14 +44,19 @@ $string['enrolmentinstances'] = 'Enrolment methods'; $string['enrolmentnew'] = 'New enrolment in {$a}'; $string['enrolmentnewuser'] = '{$a->user} has enrolled in course "{$a->course}"'; $string['enrolments'] = 'Enrolments'; +$string['enrolmentoptions'] = 'Enrolment options'; $string['enrolperiod'] = 'Enrolment duration'; $string['enrolusage'] = 'Instances / enrolments'; +$string['enrolusers'] = 'Enrol users'; $string['enroltimeend'] = 'Enrolment ends'; $string['enroltimestart'] = 'Enrolment starts'; +$string['errajaxfailedenrol'] = 'Failed to enrol user'; +$string['errajaxsearch'] = 'Error when searching users'; $string['manageenrols'] = 'Manage enrol plugins'; $string['manageinstance'] = 'Manage'; $string['noexistingparticipants'] = 'No existing participants'; $string['noguestaccess'] = 'Guests can not access this course, please try to log in.'; +$string['none'] = 'None'; $string['notenrollable'] = 'This course is not enrollable at the moment.'; $string['notenrolledusers'] = 'Other users'; $string['participationactive'] = 'Active'; @@ -55,9 +65,12 @@ $string['participationsuspended'] = 'Suspended'; $string['periodend'] = 'until {$a}'; $string['periodstart'] = 'from {$a}'; $string['periodstartend'] = 'from {$a->start} until {$a->end}'; +$string['startdatetoday'] = 'Today'; $string['unenrol'] = 'Unenrol'; $string['unenrolconfirm'] = 'Do you really want to unenrol user "{$a->user}" from course "{$a->course}"?'; $string['unenrolme'] = 'Unenrol me from {$a}'; $string['unenrolroleusers'] = 'Unenrol users'; $string['uninstallconfirm'] = 'You are about to completely delete the enrol plugin \'{$a}\'. This will completely delete everything in the database associated with this enrolment type. Are you SURE you want to continue?'; $string['uninstalldeletefiles'] = 'All data associated with the enrol plugin \'{$a->plugin}\' has been deleted from the database. To complete the deletion (and prevent the plugin re-installing itself), you should now delete this directory from your server: {$a->directory}'; +$string['unlimitedduration'] = 'Unlmited'; +$string['usersearch'] = 'Search '; diff --git a/lib/ajax/getnavbranch.php b/lib/ajax/getnavbranch.php index 24e32bfd3d7..115580e292e 100644 --- a/lib/ajax/getnavbranch.php +++ b/lib/ajax/getnavbranch.php @@ -25,6 +25,8 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +define('AJAX_SCRIPT', true); + /** Include config */ require_once(dirname(__FILE__) . '/../../config.php'); /** Include course lib for its functions */ diff --git a/pix/t/enroladd.gif b/pix/t/enroladd.gif new file mode 100644 index 0000000000000000000000000000000000000000..3b31bf769ca5a378c76adb021ad5e874c6b451c9 GIT binary patch literal 288 zcmZ?wbhEHb(}qzy?gKe{f7@9K6>=%@uNpipFVx@;>DXc zZ$5tf_z8$Uefs?Q^Y