diff --git a/mod/lesson/lang/en/lesson.php b/mod/lesson/lang/en/lesson.php index 0b7a62a57c5..dcdc50c35ef 100644 --- a/mod/lesson/lang/en/lesson.php +++ b/mod/lesson/lang/en/lesson.php @@ -246,7 +246,7 @@ $string['gradeis'] = 'Grade is {$a}'; $string['gradeoptions'] = 'Grade options'; $string['groupoverrides'] = 'Group overrides'; $string['groupoverridesdeleted'] = 'Group overrides deleted'; -$string['groupsnone'] = 'There are no groups in this course'; +$string['groupsnone'] = 'No groups you can access.'; $string['handlingofretakes'] = 'Handling of re-takes'; $string['handlingofretakes_help'] = 'If re-takes are allowed, this setting specifies whether the grade for the lesson is the mean or maximum of all attempts.'; $string['havenotgradedyet'] = 'Have not graded yet.'; diff --git a/mod/lesson/override_form.php b/mod/lesson/override_form.php index 0d7fbed1935..ae52f8b35b3 100644 --- a/mod/lesson/override_form.php +++ b/mod/lesson/override_form.php @@ -81,13 +81,16 @@ class lesson_override_form extends moodleform { * Define this form - called by the parent constructor */ protected function definition() { - global $CFG, $DB; + global $DB; $cm = $this->cm; $mform = $this->_form; $mform->addElement('header', 'override', get_string('override', 'lesson')); + $lessongroupmode = groups_get_activity_groupmode($cm); + $accessallgroups = ($lessongroupmode == NOGROUPS) || has_capability('moodle/site:accessallgroups', $this->context); + if ($this->groupmode) { // Group override. if ($this->groupid) { @@ -99,7 +102,8 @@ class lesson_override_form extends moodleform { $mform->freeze('groupid'); } else { // Prepare the list of groups. - $groups = groups_get_all_groups($cm->course); + // Only include the groups the current can access. + $groups = $accessallgroups ? groups_get_all_groups($cm->course) : groups_get_activity_allowed_groups($cm); if (empty($groups)) { // Generate an error. $link = new moodle_url('/mod/lesson/overrides.php', array('cmid' => $cm->id)); @@ -132,8 +136,27 @@ class lesson_override_form extends moodleform { $mform->freeze('userid'); } else { // Prepare the list of users. - $users = get_enrolled_users($this->context, '', 0, - 'u.id, u.email, ' . get_all_user_name_fields(true, 'u')); + $users = []; + list($sort) = users_order_by_sql('u'); + + // Get the list of appropriate users, depending on whether and how groups are used. + if ($accessallgroups) { + $users = get_enrolled_users($this->context, '', 0, + 'u.id, u.email, ' . get_all_user_name_fields(true, 'u'), $sort); + } else if ($groups = groups_get_activity_allowed_groups($cm)) { + $enrolledjoin = get_enrolled_join($this->context, 'u.id'); + $userfields = 'u.id, u.email, ' . get_all_user_name_fields(true, 'u'); + list($ingroupsql, $ingroupparams) = $DB->get_in_or_equal(array_keys($groups), SQL_PARAMS_NAMED); + $params = $enrolledjoin->params + $ingroupparams; + $sql = "SELECT $userfields + FROM {user} u + JOIN {groups_members} gm ON gm.userid = u.id + {$enrolledjoin->joins} + WHERE gm.groupid $ingroupsql + AND {$enrolledjoin->wheres} + ORDER BY $sort"; + $users = $DB->get_records_sql($sql, $params); + } // Filter users based on any fixed restrictions (groups, profile). $info = new \core_availability\info_module($cm); @@ -235,7 +258,6 @@ class lesson_override_form extends moodleform { * @return array of "element_name"=>"error_description" if there are errors */ public function validation($data, $files) { - global $COURSE, $DB; $errors = parent::validation($data, $files); $mform =& $this->_form; diff --git a/mod/lesson/overrides.php b/mod/lesson/overrides.php index be60a7787ab..657dcfb4b19 100644 --- a/mod/lesson/overrides.php +++ b/mod/lesson/overrides.php @@ -35,11 +35,18 @@ $mode = optional_param('mode', '', PARAM_ALPHA); // One of 'user' or 'group', de list($course, $cm) = get_course_and_cm_from_cmid($cmid, 'lesson'); $lesson = $DB->get_record('lesson', array('id' => $cm->instance), '*', MUST_EXIST); -// Get the course groups. -$groups = groups_get_all_groups($cm->course); -if ($groups === false) { - $groups = array(); -} +require_login($course, false, $cm); + +$context = context_module::instance($cm->id); + +// Check the user has the required capabilities to list overrides. +require_capability('mod/lesson:manageoverrides', $context); + +$lessongroupmode = groups_get_activity_groupmode($cm); +$accessallgroups = ($lessongroupmode == NOGROUPS) || has_capability('moodle/site:accessallgroups', $context); + +// Get the course groups that the current user can access. +$groups = $accessallgroups ? groups_get_all_groups($cm->course) : groups_get_activity_allowed_groups($cm); // Default mode is "group", unless there are no groups. if ($mode != "user" and $mode != "group") { @@ -55,13 +62,6 @@ $url = new moodle_url('/mod/lesson/overrides.php', array('cmid' => $cm->id, 'mod $PAGE->set_url($url); -require_login($course, false, $cm); - -$context = context_module::instance($cm->id); - -// Check the user has the required capabilities to list overrides. -require_capability('mod/lesson:manageoverrides', $context); - // Display a list of overrides. $PAGE->set_pagelayout('admin'); $PAGE->set_title(get_string('overrides', 'lesson')); @@ -71,35 +71,62 @@ echo $OUTPUT->heading(format_string($lesson->name, true, array('context' => $con // Delete orphaned group overrides. $sql = 'SELECT o.id - FROM {lesson_overrides} o LEFT JOIN {groups} g - ON o.groupid = g.id - WHERE o.groupid IS NOT NULL - AND g.id IS NULL - AND o.lessonid = ?'; + FROM {lesson_overrides} o + LEFT JOIN {groups} g ON o.groupid = g.id + WHERE o.groupid IS NOT NULL + AND g.id IS NULL + AND o.lessonid = ?'; $params = array($lesson->id); $orphaned = $DB->get_records_sql($sql, $params); if (!empty($orphaned)) { $DB->delete_records_list('lesson_overrides', 'id', array_keys($orphaned)); } +$overrides = []; + // Fetch all overrides. if ($groupmode) { $colname = get_string('group'); - $sql = 'SELECT o.*, g.name - FROM {lesson_overrides} o - JOIN {groups} g ON o.groupid = g.id - WHERE o.lessonid = :lessonid - ORDER BY g.name'; - $params = array('lessonid' => $lesson->id); + // To filter the result by the list of groups that the current user has access to. + if ($groups) { + $params = ['lessonid' => $lesson->id]; + list($insql, $inparams) = $DB->get_in_or_equal(array_keys($groups), SQL_PARAMS_NAMED); + $params += $inparams; + + $sql = "SELECT o.*, g.name + FROM {lesson_overrides} o + JOIN {groups} g ON o.groupid = g.id + WHERE o.lessonid = :lessonid AND g.id $insql + ORDER BY g.name"; + + $overrides = $DB->get_records_sql($sql, $params); + } } else { $colname = get_string('user'); list($sort, $params) = users_order_by_sql('u'); - $sql = 'SELECT o.*, ' . get_all_user_name_fields(true, 'u') . ' - FROM {lesson_overrides} o - JOIN {user} u ON o.userid = u.id - WHERE o.lessonid = :lessonid - ORDER BY ' . $sort; $params['lessonid'] = $lesson->id; + + if ($accessallgroups) { + $sql = 'SELECT o.*, ' . get_all_user_name_fields(true, 'u') . ' + FROM {lesson_overrides} o + JOIN {user} u ON o.userid = u.id + WHERE o.lessonid = :lessonid + ORDER BY ' . $sort; + + $overrides = $DB->get_records_sql($sql, $params); + } else if ($groups) { + list($insql, $inparams) = $DB->get_in_or_equal(array_keys($groups), SQL_PARAMS_NAMED); + $params += $inparams; + + $sql = 'SELECT o.*, ' . get_all_user_name_fields(true, 'u') . ' + FROM {lesson_overrides} o + JOIN {user} u ON o.userid = u.id + JOIN {groups_members} gm ON u.id = gm.userid + WHERE o.lessonid = :lessonid AND gm.groupid ' . $insql . ' + ORDER BY ' . $sort; + + $overrides = $DB->get_records_sql($sql, $params); + } } $overrides = $DB->get_records_sql($sql, $params); @@ -272,13 +299,31 @@ if ($groupmode) { } else { $users = array(); // See if there are any users in the lesson. - $users = get_enrolled_users($context); + if ($accessallgroups) { + $users = get_enrolled_users($context, '', 0, 'u.id'); + $nousermessage = get_string('usersnone', 'lesson'); + } else if ($groups) { + $enrolledjoin = get_enrolled_join($context, 'u.id'); + list($ingroupsql, $ingroupparams) = $DB->get_in_or_equal(array_keys($groups), SQL_PARAMS_NAMED); + $params = $enrolledjoin->params + $ingroupparams; + $sql = "SELECT u.id + FROM {user} u + JOIN {groups_members} gm ON gm.userid = u.id + {$enrolledjoin->joins} + WHERE gm.groupid $ingroupsql + AND {$enrolledjoin->wheres} + ORDER BY $sort"; + $users = $DB->get_records_sql($sql, $params); + $nousermessage = get_string('usersnone', 'lesson'); + } else { + $nousermessage = get_string('groupsnone', 'lesson'); + } $info = new \core_availability\info_module($cm); $users = $info->filter_user_list($users); if (empty($users)) { // There are no users. - echo $OUTPUT->notification(get_string('usersnone', 'lesson'), 'error'); + echo $OUTPUT->notification($nousermessage, 'error'); $options['disabled'] = true; } echo $OUTPUT->single_button($overrideediturl->out(true, diff --git a/mod/lesson/tests/behat/lesson_group_override.feature b/mod/lesson/tests/behat/lesson_group_override.feature index d28ccbf40c1..ea7b8860f25 100644 --- a/mod/lesson/tests/behat/lesson_group_override.feature +++ b/mod/lesson/tests/behat/lesson_group_override.feature @@ -48,8 +48,11 @@ Feature: Lesson group override | id_response_editor_1 | Wrong | | id_jumpto_1 | This page | And I press "Save page" + And I log out Scenario: Add, modify then delete a group override + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Group overrides" in current page administration And I press "Add group override" @@ -73,6 +76,8 @@ Feature: Lesson group override And I should not see "Group 1" Scenario: Duplicate a user override + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Group overrides" in current page administration And I press "Add group override" @@ -95,6 +100,8 @@ Feature: Lesson group override And I should see "Group 2" Scenario: Allow a single group to have re-take the lesson + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -134,6 +141,8 @@ Feature: Lesson group override And I should see "You are not allowed to retake this lesson." Scenario: Allow a single group to have a different password + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -179,6 +188,8 @@ Feature: Lesson group override And I press "Continue" Scenario: Allow a group to have a different due date + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -214,6 +225,8 @@ Feature: Lesson group override And I should see "Cat is an amphibian" Scenario: Allow a group to have a different start date + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -249,6 +262,8 @@ Feature: Lesson group override And I should see "Cat is an amphibian" Scenario: Allow a single group to have multiple attempts at each question + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -289,6 +304,8 @@ Feature: Lesson group override @javascript Scenario: Add both a user and group override and verify that both are applied correctly + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -340,3 +357,76 @@ Feature: Lesson group override And I am on "Course 1" course homepage And I follow "Test lesson" And I should see "This lesson will be open on Wednesday, 1 January 2020, 8:00" + + Scenario: Override a group when teacher is in no group, and does not have accessallgroups permission, and the activity's group mode is 'separate groups' + Given the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 | + And the following "activities" exist: + | activity | name | intro | course | idnumber | groupmode | + | lesson | Lesson 2 | Lesson 2 description | C1 | lesson2 | 1 | + When I log in as "teacher1" + And I am on "Course 1" course homepage + And I follow "Lesson 2" + And I navigate to "Group overrides" in current page administration + Then I should see "No groups you can access." + And the "Add group override" "button" should be disabled + + Scenario: A teacher without accessallgroups permission should only be able to add group override for their groups, when the activity's group mode is 'separate groups' + Given the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 | + And the following "activities" exist: + | activity | name | intro | course | idnumber | groupmode | + | lesson | Lesson 2 | Lesson 2 description | C1 | lesson2 | 1 | + And the following "group members" exist: + | user | group | + | teacher1 | G1 | + When I log in as "teacher1" + And I am on "Course 1" course homepage + And I follow "Lesson 2" + And I navigate to "Group overrides" in current page administration + And I press "Add group override" + Then the "Override group" select box should contain "Group 1" + And the "Override group" select box should not contain "Group 2" + + Scenario: A teacher without accessallgroups permission should only be able to see the group overrides for their groups, when the activity's group mode is 'separate groups' + Given the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 | + And the following "activities" exist: + | activity | name | intro | course | idnumber | groupmode | + | lesson | Lesson 2 | Lesson 2 description | C1 | lesson2 | 1 | + And the following "group members" exist: + | user | group | + | teacher1 | G1 | + And I log in as "admin" + And I am on "Course 1" course homepage + And I follow "Lesson 2" + And I navigate to "Group overrides" in current page administration + And I press "Add group override" + And I set the following fields to these values: + | Override group | Group 1 | + | id_available_enabled | 1 | + | available[day] | 1 | + | available[month] | January | + | available[year] | 2020 | + | available[hour] | 08 | + | available[minute] | 00 | + And I press "Save and enter another override" + And I set the following fields to these values: + | Override group | Group 2 | + | id_available_enabled | 1 | + | available[day] | 1 | + | available[month] | January | + | available[year] | 2020 | + | available[hour] | 08 | + | available[minute] | 00 | + And I press "Save" + And I log out + When I log in as "teacher1" + And I am on "Course 1" course homepage + And I follow "Lesson 2" + And I navigate to "Group overrides" in current page administration + Then I should see "Group 1" in the ".generaltable" "css_element" + And I should not see "Group 2" in the ".generaltable" "css_element" diff --git a/mod/lesson/tests/behat/lesson_user_override.feature b/mod/lesson/tests/behat/lesson_user_override.feature index 5612457f85c..495f5085d66 100644 --- a/mod/lesson/tests/behat/lesson_user_override.feature +++ b/mod/lesson/tests/behat/lesson_user_override.feature @@ -1,4 +1,4 @@ -@mod @mod_lesson @javascript +@mod @mod_lesson Feature: Lesson user override In order to grant a student special access to a lesson As a teacher @@ -18,10 +18,6 @@ Feature: Lesson user override | teacher1 | C1 | editingteacher | | student1 | C1 | student | | student2 | C1 | student | - And the following "groups" exist: - | name | course | idnumber | - | Group 1 | C1 | G1 | - | Group 2 | C1 | G2 | And the following "activities" exist: | activity | name | intro | course | idnumber | | lesson | Test lesson name | Test lesson description | C1 | lesson1 | @@ -41,9 +37,12 @@ Feature: Lesson user override | id_response_editor_1 | Wrong | | id_jumpto_1 | This page | And I press "Save page" + And I log out @javascript Scenario: Add, modify then delete a user override + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "User overrides" in current page administration And I press "Add user override" @@ -66,7 +65,10 @@ Feature: Lesson user override And I press "Continue" And I should not see "Sam1 Student1" + @javascript Scenario: Duplicate a user override + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "User overrides" in current page administration And I press "Add user override" @@ -88,7 +90,10 @@ Feature: Lesson user override And I should see "Tuesday, 1 January 2030, 8:00" And I should see "Sam2 Student2" + @javascript Scenario: Allow a single user to have re-take the lesson + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -127,7 +132,10 @@ Feature: Lesson user override And I follow "Test lesson name" And I should see "You are not allowed to retake this lesson." + @javascript Scenario: Allow a single user to have a different password + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -172,7 +180,10 @@ Feature: Lesson user override And I set the field "userpassword" to "moodle_rules" And I press "Continue" + @javascript Scenario: Allow a user to have a different due date + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -207,7 +218,10 @@ Feature: Lesson user override And I follow "Test lesson" And I should see "Cat is an amphibian" + @javascript Scenario: Allow a user to have a different start date + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -242,7 +256,10 @@ Feature: Lesson user override And I follow "Test lesson" And I should see "Cat is an amphibian" + @javascript Scenario: Allow a single user to have multiple attempts at each question + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I follow "Test lesson name" And I navigate to "Edit settings" in current page administration And I set the following fields to these values: @@ -280,3 +297,89 @@ Feature: Lesson user override And I press "Submit" Then I press "Continue" And I should see "Congratulations - end of lesson reached" + + Scenario: Override a user when teacher is in no group, and does not have accessallgroups permission, and the activity's group mode is 'separate groups' + Given the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 | + And the following "activities" exist: + | activity | name | intro | course | idnumber | groupmode | + | lesson | Lesson 2 | Lesson 2 description | C1 | lesson2 | 1 | + When I log in as "teacher1" + And I am on "Course 1" course homepage + And I follow "Lesson 2" + And I navigate to "User overrides" in current page administration + Then I should see "No groups you can access." + And the "Add user override" "button" should be disabled + + Scenario: A teacher without accessallgroups permission should only be able to add user override for their group-mates, when the activity's group mode is 'separate groups' + Given the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 | + And the following "activities" exist: + | activity | name | intro | course | idnumber | groupmode | + | lesson | Lesson 2 | Lesson 2 description | C1 | lesson2 | 1 | + And the following "groups" exist: + | name | course | idnumber | + | Group 1 | C1 | G1 | + | Group 2 | C1 | G2 | + And the following "group members" exist: + | user | group | + | teacher1 | G1 | + | student1 | G1 | + | student2 | G2 | + When I log in as "teacher1" + And I am on "Course 1" course homepage + And I follow "Lesson 2" + And I navigate to "User overrides" in current page administration + And I press "Add user override" + Then the "Override user" select box should contain "Sam1 Student1, student1@example.com" + And the "Override user" select box should not contain "Sam2 Student2, student2@example.com" + + @javascript + Scenario: A teacher without accessallgroups permission should only be able to see the user override for their group-mates, when the activity's group mode is 'separate groups' + Given the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 | + And the following "activities" exist: + | activity | name | intro | course | idnumber | groupmode | + | lesson | Lesson 2 | Lesson 2 description | C1 | lesson2 | 1 | + And the following "groups" exist: + | name | course | idnumber | + | Group 1 | C1 | G1 | + | Group 2 | C1 | G2 | + And the following "group members" exist: + | user | group | + | teacher1 | G1 | + | student1 | G1 | + | student2 | G2 | + And I log in as "admin" + And I am on "Course 1" course homepage + And I follow "Lesson 2" + And I navigate to "User overrides" in current page administration + And I press "Add user override" + And I set the following fields to these values: + | Override user | Student1 | + | id_deadline_enabled | 1 | + | deadline[day] | 1 | + | deadline[month] | January | + | deadline[year] | 2020 | + | deadline[hour] | 08 | + | deadline[minute] | 00 | + And I press "Save and enter another override" + And I set the following fields to these values: + | Override user | Student2 | + | id_deadline_enabled | 1 | + | deadline[day] | 1 | + | deadline[month] | January | + | deadline[year] | 2020 | + | deadline[hour] | 08 | + | deadline[minute] | 00 | + And I press "Save" + And I log out + When I log in as "teacher1" + And I am on "Course 1" course homepage + And I follow "Lesson 2" + And I navigate to "User overrides" in current page administration + Then I should see "Student1" in the ".generaltable" "css_element" + And I should not see "Student2" in the ".generaltable" "css_element"