From fa80221069e31b70b679147a9c07e2770c2a9d42 Mon Sep 17 00:00:00 2001 From: Adam Olley Date: Thu, 19 Jul 2012 12:44:41 +0930 Subject: [PATCH] New Feature: per-group limits --- .../moodle2/backup_groupselect_stepslib.php | 16 ++- .../moodle2/restore_groupselect_stepslib.php | 13 ++ db/install.xml | 21 ++- db/upgrade.php | 13 ++ lang/en/groupselect.php | 3 + lib.php | 23 ++++ limits.php | 130 ++++++++++++++++++ limits_form.php | 53 +++++++ locallib.php | 63 +++++++++ version.php | 2 +- view.php | 17 ++- 11 files changed, 346 insertions(+), 8 deletions(-) create mode 100644 limits.php create mode 100644 limits_form.php diff --git a/backup/moodle2/backup_groupselect_stepslib.php b/backup/moodle2/backup_groupselect_stepslib.php index 20a8cba..ae144db 100644 --- a/backup/moodle2/backup_groupselect_stepslib.php +++ b/backup/moodle2/backup_groupselect_stepslib.php @@ -38,17 +38,31 @@ protected function define_structure() { // Define each element separated $groupselect = new backup_nested_element('groupselect', array('id'), array( 'name', 'intro', 'introformat', 'targetgrouping', 'contentformat', - 'password', 'maxmembers', 'timeavailable', 'timedue', + 'password', 'maxmembers', 'individual_limits', 'timeavailable', 'timedue', 'timecreated', 'timemodified')); + $limits = new backup_nested_element('limits'); + + $limit = new backup_nested_element('limit', array('id'), array( + 'groupselect', 'groupid', 'lim')); + // Build the tree // (love this) + $groupselect->add_child($limits); + $limits->add_child($limit); // Define sources $groupselect->set_source_table('groupselect', array('id' => backup::VAR_ACTIVITYID)); + $limit->set_source_sql(' + SELECT * + FROM {groupselect_limits} + WHERE groupselect = ?', + array(backup::VAR_PARENTID) + ); // Define id annotations // (none) + $limit->annotate_ids('group', 'groupid'); // Define file annotations $groupselect->annotate_files('mod_groupselect', 'intro', null); // This file areas haven't itemid diff --git a/backup/moodle2/restore_groupselect_stepslib.php b/backup/moodle2/restore_groupselect_stepslib.php index 9317022..824c3b3 100644 --- a/backup/moodle2/restore_groupselect_stepslib.php +++ b/backup/moodle2/restore_groupselect_stepslib.php @@ -32,6 +32,7 @@ protected function define_structure() { $paths = array(); $paths[] = new restore_path_element('groupselect', '/activity/groupselect'); + $paths[] = new restore_path_element('groupselect_limit', '/activity/groupselect/limits/limit'); // Return the paths wrapped into standard activity structure return $this->prepare_activity_structure($paths); @@ -53,6 +54,18 @@ protected function process_groupselect($data) { $this->apply_activity_instance($newitemid); } + protected function process_groupselect_limit($data) { + global $DB; + + $data = (object)$data; + $oldid = $data->id; + + $data->groupselect = $this->get_new_parentid('groupselect'); + $data->groupid = $this->get_mappingid('group', $data->groupid); + + $newitemid = $DB->insert_record('groupselect_limits', $data); + } + protected function after_execute() { // Add groupselect related files, no need to match by itemname (just internally handled context) $this->add_related_files('mod_groupselect', 'intro', null); diff --git a/db/install.xml b/db/install.xml index dbcef3d..f6bae56 100644 --- a/db/install.xml +++ b/db/install.xml @@ -4,7 +4,7 @@ xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd" > - +
@@ -13,8 +13,9 @@ - - + + + @@ -26,5 +27,19 @@
+ + + + + + + + + + + + + +
diff --git a/db/upgrade.php b/db/upgrade.php index 1e896b3..9358a81 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -106,6 +106,19 @@ function xmldb_groupselect_upgrade($oldversion) { upgrade_mod_savepoint(true, 2011101800, 'groupselect'); } + if ($oldversion < 2012071900) { + $table = new xmldb_table('groupselect'); + $field = new xmldb_field('individual_limits'); + $field->set_attributes(XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); + $dbman->add_field($table, $field); + + $table = new xmldb_table('groupselect_limits'); + if (!$dbman->table_exists($table)) { + $dbman->install_one_table_from_xmldb_file($CFG->dirroot.'/mod/groupselect/db/install.xml', 'groupselect_limits', true); + } + + upgrade_mod_savepoint(true, 2012071900, 'groupselect'); + } return true; } diff --git a/lang/en/groupselect.php b/lang/en/groupselect.php index d34f8c5..2609f3e 100644 --- a/lang/en/groupselect.php +++ b/lang/en/groupselect.php @@ -11,6 +11,9 @@ $string['groupselect:select'] = 'Allow becoming of group member'; $string['groupselect:unselect'] = 'Allow leaving of group'; $string['incorrectpassword'] = 'Incorrect password'; +$string['limit'] = 'Limit'; +$string['limits'] = 'Limits'; +$string['limits_intro'] = 'Use this page to configure the "max members per group" setting on a per-group basis. If a box is left empty, the group will be limited to the default number set on the main configuration page (currently {$a}). A value of 0 indicates that unlimited members are allowed.'; $string['managegroups'] = 'Manage groups'; $string['maxlimitreached'] = 'Maximum number reached'; $string['maxmembers'] = 'Max members per group'; diff --git a/lib.php b/lib.php index 9b64750..51f8a4d 100644 --- a/lib.php +++ b/lib.php @@ -199,3 +199,26 @@ function groupselect_reset_userdata($data) { // no resetting here - all data is stored in the group tables return array(); } + +/** + * Adds module specific settings to the settings block + * + * @param settings_navigation $settings The settings navigation object + * @param navigation_node $forumnode The node to add module settings to + */ +function groupselect_extend_settings_navigation(settings_navigation $settingsnav, navigation_node $groupselectnode) { + global $USER, $PAGE, $CFG, $DB, $OUTPUT; + + $groupselectobject = $DB->get_record("groupselect", array("id" => $PAGE->cm->instance)); + if (empty($PAGE->cm->context)) { + $PAGE->cm->context = get_context_instance(CONTEXT_MODULE, $PAGE->cm->instance); + } + + $canmanage = has_capability('moodle/course:managegroups', $PAGE->cm->context); + + if ($canmanage) { + $url = new moodle_url('/mod/groupselect/limits.php', array('id' => $PAGE->cm->id)); + $string = get_string('limits', 'groupselect'); + $groupselectnode->add($string, $url, settings_navigation::TYPE_SETTING); + } +} diff --git a/limits.php b/limits.php new file mode 100644 index 0000000..bb3c7f4 --- /dev/null +++ b/limits.php @@ -0,0 +1,130 @@ +. + +/** + * Group limit interface + * + * @package mod_groupselect + * @author Adam Olley + * @copyright 2012 NetSpot Pty Ltd + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../config.php'); +require_once('locallib.php'); +require_once('limits_form.php'); + +$id = required_param('id', PARAM_INT); // Course Module ID, or +$signup = optional_param('signup', 0, PARAM_INT); +$confirm = optional_param('confirm', 0, PARAM_BOOL); + +$params = array(); +$params['id'] = $id; +if ($signup) { + $params['signup'] = $signup; +} +if ($confirm) { + $params['confirm'] = $confirm; +} + +if (!$cm = get_coursemodule_from_id('groupselect', $id)) { + print_error('invalidcoursemodule'); +} + +if (!$course = $DB->get_record('course', array('id' => $cm->course))) { + print_error('coursemisconf'); +} + +if (!$groupselect = $DB->get_record('groupselect', array('id' => $cm->instance))) { + print_error('invalidcoursemodule'); +} + +$PAGE->set_url('/mod/groupselect/limits.php'); + +require_login($course, true, $cm); +$context = get_context_instance(CONTEXT_MODULE, $cm->id); +require_capability('moodle/course:managegroups', $context); + +$groups = groups_get_all_groups($course->id, 0, $groupselect->targetgrouping); + +if ($course->id == SITEID) { + $viewothers = has_capability('moodle/site:viewparticipants', $sitecontext); +} else { + $viewothers = has_capability('moodle/course:viewparticipants', $context); +} + +$strlimit = get_string('modulename', 'groupselect') . ' - ' . get_string('limits', 'groupselect'); +$strgroupselect = get_string('modulename', 'groupselect'); + +$PAGE->set_title(format_string($groupselect->name)); +$PAGE->set_heading($course->fullname); +$PAGE->set_cacheable(true); +$PAGE->set_cm($cm); +$PAGE->set_context($context); +$PAGE->set_pagelayout('incourse'); + +$mform = new mod_groupselect_limits_form($groups); +$formdata = array('id' => $id); +$formdata = array_merge($formdata, groupselect_retrieve_limits_formdata($groupselect->id)); + +if ($data = $mform->get_data()) { + // Save form data. + if ($data->limit) { + $limits = array(); + foreach ($data->limit as $groupid => $lim) { + if ($lim === '') { + continue; + } + $lim = intval($lim); + $limits[$groupid] = $lim; + } + groupselect_save_limits($groupselect->id, $limits); + } + redirect("$CFG->wwwroot/mod/groupselect/view.php?id=$id"); +} + +echo $OUTPUT->header(); +echo ''; + +if (empty($CFG->enablegroupings) or empty($cm->groupingid)) { + echo $OUTPUT->heading(get_string('pluginname', 'groupselect')); +} else { + $grouping = groups_get_grouping($cm->groupingid); + echo $OUTPUT->heading(get_string('pluginname', 'groupselect').' '.format_string($grouping->name)); +} + +echo $OUTPUT->box(get_string('limits_intro', 'groupselect', intval($groupselect->maxmembers)), + 'intro generalbox boxwidthnormal boxaligncenter'); +if ($groups) { + $data = array(); + + foreach ($groups as $group) { + $ismember = isset($mygroups[$group->id]); + $usercount = isset($counts[$group->id]) ? $counts[$group->id]->usercount : 0; + $grpname = format_string($group->name); + + $line = array(); + if ($ismember) { + $grpname = '
'.$grpname.'
'; + } + } +} else { + echo $OUTPUT->notification(get_string('nogroups', 'groupselect')); +} +$mform->set_data($formdata); +$mform->display(); + +echo $OUTPUT->footer(); diff --git a/limits_form.php b/limits_form.php new file mode 100644 index 0000000..4c799ae --- /dev/null +++ b/limits_form.php @@ -0,0 +1,53 @@ +. + +/** + * Group limit interface form + * + * @package mod_groupselect + * @author Adam Olley + * @copyright 2012 NetSpot Pty Ltd + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once ($CFG->dirroot.'/course/moodleform_mod.php'); + +class mod_groupselect_limits_form extends moodleform { + + public function mod_groupselect_limits_form ($groups) { + $this->groups = $groups; + parent::moodleform(); + } + + public function definition() { + global $COURSE; + + $mform =& $this->_form; + + $strlimit = get_string('limit', 'groupselect'); + + $mform->addElement('hidden', 'id'); + $mform->setType('id', PARAM_INT); + + foreach ($this->groups as $group) { + $elname = 'limit[' . $group->id . ']'; + $mform->addElement('text', $elname, $group->name . ' ' . $strlimit, array('size' => 4)); + $mform->setType($elname, PARAM_INT); + } + + $this->add_action_buttons(); + } +} diff --git a/locallib.php b/locallib.php index 95b39ae..8507532 100644 --- a/locallib.php +++ b/locallib.php @@ -88,3 +88,66 @@ function groupselect_group_member_counts($cm, $targetgrouping=0) { return $DB->get_records_sql($sql, $params); } + +function groupselect_save_limits($groupselectid, $limits) { + global $DB; + $groupselectid = intval($groupselectid); + # query for existing records which we can update or delete + if ($rs = $DB->get_recordset_select('groupselect_limits', "groupselect = $groupselectid", + null, '', 'id, groupselect, groupid, lim')) { + # array to store IDs of rows we want to delete + $delete = array(); + foreach ($rs as $grouplimit) { + if (isset($limits[$grouplimit->groupid])) { + if ($limits[$grouplimit->groupid] != $grouplimit->lim) { + # only need to update the row if the new limit is different to the + # existing record + $grouplimit->lim = $limits[$grouplimit->groupid]; + $DB->update_record('groupselect_limits', $grouplimit); + } + } else { + # a limit for this groupid was left blank, so remove the row + $delete[] = $grouplimit->id; + } + unset($limits[$grouplimit->groupid]); + } + $rs->close(); + + if (!empty($delete)) { + list($insql, $params) = $DB->get_in_or_equal($delete); + $DB->delete_records_select('groupselect_limits', "id $insql", $params); + } + } + + # insert all remaining limits + foreach ($limits as $groupid => $lim) { + $grouplimit = new object(); + $grouplimit->groupselect = $groupselectid; + $grouplimit->groupid = $groupid; + $grouplimit->lim = $lim; + $DB->insert_record('groupselect_limits', $grouplimit); + } +} + +function groupselect_retrieve_limits_formdata($groupselectid) { + global $DB; + $formdata = array(); + if ($grouplimits = $DB->get_records("groupselect_limits", array("groupselect" => $groupselectid))) { + foreach ($grouplimits as $grouplimit) { + $formdata['limit['.$grouplimit->groupid . ']'] = $grouplimit->lim; + } + } + return $formdata; +} + +function groupselect_get_limits($groupselectid) { + global $DB; + $limits = array(); + if ($grouplimits = $DB->get_records("groupselect_limits", array("groupselect" => $groupselectid))) { + foreach ($grouplimits as $grouplimit) { + $limits[$grouplimit->groupid] = $grouplimit->lim; + } + } + + return $limits; +} diff --git a/version.php b/version.php index 34620ab..099c721 100644 --- a/version.php +++ b/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die; -$module->version = 2012042100; // The current module version (Date: YYYYMMDDXX) +$module->version = 2012071900; // The current module version (Date: YYYYMMDDXX) $module->requires = 2011070101; // Requires this Moodle version $module->cron = 0; // Period for cron to check this module (secs) $module->component = 'mod_groupselect'; // Full name of the plugin (used for diagnostics) diff --git a/view.php b/view.php index 8de109d..48bbbdd 100644 --- a/view.php +++ b/view.php @@ -102,6 +102,12 @@ $grpname = format_string($groups[$select]->name, true, array('context'=>$context)); $usercount = isset($counts[$select]) ? $counts[$select]->usercount : 0; + $limits = groupselect_get_limits($groupselect->id); + $signuplimit = isset($limits[$signup]) ? $limits[$signup] : $groupselect->maxmembers; + if ($signuplimit <= $usercount && $signuplimit != 0) { + print_error(get_string('maxlimitreached', 'groupselect')); + } + $data = array('id'=>$id, 'select'=>$select); $mform = new select_form(null, array($data, $groupselect, $grpname)); @@ -175,11 +181,14 @@ $data = array(); $actionpresent = false; + $limits = groupselect_get_limits($groupselect->id); foreach ($groups as $group) { $ismember = isset($mygroups[$group->id]); $usercount = isset($counts[$group->id]) ? $counts[$group->id]->usercount : 0; $grpname = format_string($group->name, true, array('context'=>$context)); + $maxorlimitmembers = isset($limits[$group->id]) ? $limits[$group->id] : $groupselect->maxmembers; + $line = array(); if ($ismember) { @@ -190,8 +199,8 @@ $line[1] = groupselect_get_group_info($group); - if ($groupselect->maxmembers) { - $line[2] = $usercount.'/'.$groupselect->maxmembers; + if ($maxorlimitmembers) { + $line[2] = $usercount.'/'.$maxorlimitmembers; } else { $line[2] = $usercount; } @@ -225,7 +234,7 @@ $line[3] = '
'.get_string('membershidden', 'mod_groupselect').'
'; } if ($isopen and !$accessall) { - if (!$ismember and $canselect and $groupselect->maxmembers and $groupselect->maxmembers <= $usercount) { + if (!$ismember and $canselect and $maxorlimitmembers and $maxorlimitmembers <= $usercount) { $line[4] = '
'.get_string('maxlimitreached', 'mod_groupselect').'
'; // full - no more members $actionpresent = true; } else if ($ismember and $canunselect) { @@ -234,6 +243,8 @@ } else if (!$ismember and $canselect) { $line[4] = $OUTPUT->single_button(new moodle_url('/mod/groupselect/view.php', array('id'=>$cm->id, 'select'=>$group->id)), get_string('select', 'mod_groupselect', $grpname)); $actionpresent = true; + } else { + $line[4] = ''; } } $data[] = $line;