Merge branch 'MDL-57411-master' of git://github.com/jleyva/moodle
authorDan Poltawski <dan@moodle.com>
Mon, 3 Apr 2017 16:59:34 +0000 (17:59 +0100)
committerDan Poltawski <dan@moodle.com>
Mon, 3 Apr 2017 16:59:34 +0000 (17:59 +0100)
lib/grouplib.php
lib/tests/grouplib_test.php
mod/assign/lib.php
mod/assign/locallib.php
mod/data/lib.php
mod/feedback/lib.php
mod/lesson/lib.php
mod/lti/lib.php
mod/quiz/lib.php
mod/scorm/lib.php
mod/survey/lib.php

index 9b57e25..90e6a0c 100644 (file)
@@ -426,10 +426,7 @@ function groups_has_membership($cm, $userid=null) {
 function groups_get_members($groupid, $fields='u.*', $sort='lastname ASC') {
     global $DB;
 
-    return $DB->get_records_sql("SELECT $fields
-                                   FROM {user} u, {groups_members} gm
-                                  WHERE u.id = gm.userid AND gm.groupid = ?
-                               ORDER BY $sort", array($groupid));
+    return groups_get_groups_members([$groupid], $fields, $sort);
 }
 
 
@@ -1133,3 +1130,47 @@ function groups_user_groups_visible($course, $userid, $cm = null) {
     }
     return false;
 }
+
+/**
+ * Returns the users in the specified groups.
+ *
+ * @param array $groupsids The list of groups ids to check
+ * @param int $fields The fields to return
+ * @param int $sort optional sorting of returned users
+ * @return array|bool Returns an array of the users for the specified group or false if no users or an error returned.
+ * @since  Moodle 3.3
+ */
+function groups_get_groups_members($groupsids, $fields='u.*', $sort='lastname ASC') {
+    global $DB;
+
+    list($insql, $params) = $DB->get_in_or_equal($groupsids);
+
+    return $DB->get_records_sql("SELECT $fields
+                                   FROM {user} u, {groups_members} gm
+                                  WHERE u.id = gm.userid AND gm.groupid $insql
+                               GROUP BY u.id
+                               ORDER BY $sort", $params);
+}
+
+/**
+ * Returns users who share group membership with the specified user in the given actiivty.
+ *
+ * @param stdClass|cm_info $cm course module
+ * @param int $userid user id (empty for current user)
+ * @return array a list of user
+ * @since  Moodle 3.3
+ */
+function groups_get_activity_shared_group_members($cm, $userid = null) {
+    global $USER;
+
+    if (empty($userid)) {
+        $userid = $USER;
+    }
+
+    $groupsids = array_keys(groups_get_activity_allowed_groups($cm, $userid));
+    // No groups no users.
+    if (empty($groupsids)) {
+        return [];
+    }
+    return groups_get_groups_members($groupsids);
+}
index e1b4618..10be269 100644 (file)
@@ -1388,4 +1388,138 @@ class core_grouplib_testcase extends advanced_testcase {
         $result = groups_user_groups_visible($course, $user1->id, $cm);
         $this->assertTrue($result); // Cm with visible groups.
     }
+
+    /**
+     * Tests for groups_get_groups_members() method.
+     */
+    public function test_groups_get_groups_members() {
+        $this->resetAfterTest(true);
+        $generator = $this->getDataGenerator();
+
+        // Create courses.
+        $course1 = $generator->create_course();
+        $course2 = $generator->create_course();
+
+        // Create users.
+        $user1 = $generator->create_user();
+        $user2 = $generator->create_user();
+        $user3 = $generator->create_user();
+
+        // Enrol users.
+        $generator->enrol_user($user1->id, $course1->id);
+        $generator->enrol_user($user1->id, $course2->id);
+        $generator->enrol_user($user2->id, $course2->id);
+        $generator->enrol_user($user3->id, $course2->id);
+
+        // Create groups.
+        $group1 = $generator->create_group(array('courseid' => $course1->id));
+        $group2 = $generator->create_group(array('courseid' => $course2->id));
+        $group3 = $generator->create_group(array('courseid' => $course2->id));
+
+        // Assign users to groups.
+        $this->assertTrue($generator->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id)));
+        $this->assertTrue($generator->create_group_member(array('groupid' => $group2->id, 'userid' => $user1->id)));
+        $this->assertTrue($generator->create_group_member(array('groupid' => $group2->id, 'userid' => $user2->id)));
+
+        // Test get_groups_members.
+        $members = groups_get_groups_members([$group1->id, $group2->id], 'u.*', 'id ASC');
+        $this->assertCount(2, $members);
+        $this->assertEquals([$user1->id, $user2->id], array_keys($members));
+
+        // Group with just one.
+        $members = groups_get_groups_members([$group1->id]);
+        $this->assertCount(1, $members);
+        $this->assertEquals($user1->id, $members[$user1->id]->id);
+
+        // Group with just one plus empty group.
+        $members = groups_get_groups_members([$group1->id, $group3->id]);
+        $this->assertCount(1, $members);
+        $this->assertEquals($user1->id, $members[$user1->id]->id);
+
+        // Empty group.
+        $members = groups_get_groups_members([$group3->id]);
+        $this->assertCount(0, $members);
+
+        // Test groups_get_members.
+        $members = groups_get_members($group2->id, 'u.*', 'id ASC');
+        $this->assertCount(2, $members);
+        $this->assertEquals([$user1->id, $user2->id], array_keys($members));
+    }
+
+    /**
+     * Tests for groups_get_activity_shared_group_members() method.
+     */
+    public function test_groups_get_activity_shared_group_members() {
+        $this->resetAfterTest(true);
+        $generator = $this->getDataGenerator();
+
+        // Create courses.
+        $course = $generator->create_course();
+
+        // Create cm.
+        $assign = $generator->create_module("assign", array('course' => $course->id));
+        $cm = get_coursemodule_from_instance("assign", $assign->id);
+
+        // Create users.
+        $user1 = $generator->create_user();
+        $user2 = $generator->create_user();
+        $user3 = $generator->create_user();
+        $user4 = $generator->create_user();
+
+        // Enrol users.
+        $generator->enrol_user($user1->id, $course->id);
+        $generator->enrol_user($user2->id, $course->id);
+        $generator->enrol_user($user3->id, $course->id);
+        $generator->enrol_user($user4->id, $course->id);
+
+        // Create groups.
+        $group1 = $generator->create_group(array('courseid' => $course->id));
+        $group2 = $generator->create_group(array('courseid' => $course->id));
+        $group3 = $generator->create_group(array('courseid' => $course->id));
+
+        // Assign users to groups.
+        $generator->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
+        $generator->create_group_member(array('groupid' => $group2->id, 'userid' => $user1->id));
+        $generator->create_group_member(array('groupid' => $group2->id, 'userid' => $user2->id));
+        $generator->create_group_member(array('groupid' => $group3->id, 'userid' => $user3->id));
+
+        // Retrieve users sharing groups with user1.
+        $members = groups_get_activity_shared_group_members($cm, $user1->id);
+        $this->assertCount(2, $members);
+        $this->assertEquals([$user1->id, $user2->id], array_keys($members), '', 0.0, 10, true);
+
+        // Retrieve users sharing groups with user2.
+        $members = groups_get_activity_shared_group_members($cm, $user2->id);
+        $this->assertCount(2, $members);
+        $this->assertEquals([$user1->id, $user2->id], array_keys($members), '', 0.0, 10, true);
+
+        // Retrieve users sharing groups with user3.
+        $members = groups_get_activity_shared_group_members($cm, $user3->id);
+        $this->assertCount(1, $members);
+        $this->assertEquals($user3->id, $members[$user3->id]->id);
+
+        // Retrieve users sharing groups with user without groups (user4).
+        $members = groups_get_activity_shared_group_members($cm, $user4->id);
+        $this->assertCount(0, $members);
+
+        // Now, create a different activity using groupings.
+        $grouping = $generator->create_grouping(array('courseid' => $course->id, 'name' => 'Grouping 1'));
+        // Skip group 2.
+        groups_assign_grouping($grouping->id, $group1->id);
+        groups_assign_grouping($grouping->id, $group3->id);
+
+        $assign = $generator->create_module("assign", array('course' => $course->id, 'groupingid' => $grouping->id));
+        $cm = get_coursemodule_from_instance("assign", $assign->id);
+
+        // Since the activity is forced to groupings (groups 1 and 3), I don't see members of group 2.
+        $members = groups_get_activity_shared_group_members($cm, $user1->id);
+        $this->assertCount(1, $members);
+        $this->assertEquals($user1->id, $members[$user1->id]->id);
+
+        // Add user1 to group 3 (in the grouping).
+        $generator->create_group_member(array('groupid' => $group3->id, 'userid' => $user1->id));
+        $members = groups_get_activity_shared_group_members($cm, $user1->id);
+        $this->assertCount(2, $members);    // Now I see members of group 3.
+        $this->assertEquals([$user1->id, $user3->id], array_keys($members), '', 0.0, 10, true);
+    }
 }
index 7852c40..b6a1807 100644 (file)
@@ -1692,5 +1692,35 @@ function assign_check_updates_since(cm_info $cm, $from, $filter = array()) {
         $updates->grades->itemids = array_keys($grades);
     }
 
+    // Now, teachers should see other students updates.
+    if (has_capability('mod/assign:viewgrades', $cm->context)) {
+        $params = array('id' => $cm->instance, 'since1' => $from, 'since2' => $from);
+        $select = 'assignment = :id AND (timecreated > :since1 OR timemodified > :since2)';
+
+        if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) {
+            $groupusers = array_keys(groups_get_activity_shared_group_members($cm));
+            if (empty($groupusers)) {
+                return $updates;
+            }
+            list($insql, $inparams) = $DB->get_in_or_equal($groupusers, SQL_PARAMS_NAMED);
+            $select .= ' AND userid ' . $insql;
+            $params = array_merge($params, $inparams);
+        }
+
+        $updates->usersubmissions = (object) array('updated' => false);
+        $submissions = $DB->get_records_select('assign_submission', $select, $params, '', 'id');
+        if (!empty($submissions)) {
+            $updates->usersubmissions->updated = true;
+            $updates->usersubmissions->itemids = array_keys($submissions);
+        }
+
+        $updates->usergrades = (object) array('updated' => false);
+        $grades = $DB->get_records_select('assign_grades', $select, $params, '', 'id');
+        if (!empty($grades)) {
+            $updates->usergrades->updated = true;
+            $updates->usergrades->itemids = array_keys($grades);
+        }
+    }
+
     return $updates;
 }
index 4deb7ba..f5a1dff 100644 (file)
@@ -5562,10 +5562,8 @@ class assign {
     public function get_shared_group_members($cm, $userid) {
         if (!isset($this->sharedgroupmembers[$userid])) {
             $this->sharedgroupmembers[$userid] = array();
-            $groupsids = array_keys(groups_get_activity_allowed_groups($cm, $userid));
-            foreach ($groupsids as $groupid) {
-                $members = array_keys(groups_get_members($groupid, 'u.id'));
-                $this->sharedgroupmembers[$userid] = array_merge($this->sharedgroupmembers[$userid], $members);
+            if ($members = groups_get_activity_shared_group_members($cm, $userid)) {
+                $this->sharedgroupmembers[$userid] = array_keys($members);
             }
         }
 
index 4498ca6..319edee 100644 (file)
@@ -4202,6 +4202,10 @@ function data_check_updates_since(cm_info $cm, $from, $filter = array()) {
     $searcharray[DATA_TIMEMODIFIED]->data    = $from;
 
     $currentgroup = groups_get_activity_group($cm);
+    // Teachers should retrieve all entries when not in separate groups.
+    if (has_capability('mod/data:manageentries', $cm->context) && groups_get_activity_groupmode($cm) != SEPARATEGROUPS) {
+        $currentgroup = 0;
+    }
     list($entries, $maxcount, $totalcount, $page, $nowperpage, $sort, $mode) =
         data_search_entries($data, $cm, $cm->context, 'list', $currentgroup, '', null, null, 0, 0, true, $searcharray);
 
index ff21e7a..3cf1d62 100644 (file)
@@ -3357,5 +3357,35 @@ function feedback_check_updates_since(cm_info $cm, $from, $filter = array()) {
         $updates->attemptsunfinished->itemids = array_keys($attemptsunfinished);
     }
 
+    // Now, teachers should see other students updates.
+    if (has_capability('mod/feedback:viewreports', $cm->context)) {
+        $select = 'feedback = ? AND timemodified > ?';
+        $params = array($cm->instance, $from);
+
+        if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) {
+            $groupusers = array_keys(groups_get_activity_shared_group_members($cm));
+            if (empty($groupusers)) {
+                return $updates;
+            }
+            list($insql, $inparams) = $DB->get_in_or_equal($groupusers);
+            $select .= ' AND userid ' . $insql;
+            $params = array_merge($params, $inparams);
+        }
+
+        $updates->userattemptsfinished = (object) array('updated' => false);
+        $attemptsfinished = $DB->get_records_select('feedback_completed', $select, $params, '', 'id');
+        if (!empty($attemptsfinished)) {
+            $updates->userattemptsfinished->updated = true;
+            $updates->userattemptsfinished->itemids = array_keys($attemptsfinished);
+        }
+
+        $updates->userattemptsunfinished = (object) array('updated' => false);
+        $attemptsunfinished = $DB->get_records_select('feedback_completedtmp', $select, $params, '', 'id');
+        if (!empty($attemptsunfinished)) {
+            $updates->userattemptsunfinished->updated = true;
+            $updates->userattemptsunfinished->itemids = array_keys($attemptsunfinished);
+        }
+    }
+
     return $updates;
 }
index 8f7526e..4130e0b 100644 (file)
@@ -1508,7 +1508,7 @@ function lesson_check_updates_since(cm_info $cm, $from, $filter = array()) {
     $updates->pages = (object) array('updated' => false);
     $updates->answers = (object) array('updated' => false);
     $select = 'lessonid = ? AND (timecreated > ? OR timemodified > ?)';
-    $params = array($cm->instance, $USER->id, $from);
+    $params = array($cm->instance, $from, $from);
 
     $pages = $DB->get_records_select('lesson_pages', $select, $params, '', 'id');
     if (!empty($pages)) {
@@ -1556,5 +1556,54 @@ function lesson_check_updates_since(cm_info $cm, $from, $filter = array()) {
         $updates->timers->itemids = array_keys($timers);
     }
 
+    // Now, teachers should see other students updates.
+    if (has_capability('mod/lesson:viewreports', $cm->context)) {
+        $select = 'lessonid = ? AND timeseen > ?';
+        $params = array($cm->instance, $from);
+
+        $insql = '';
+        $inparams = [];
+        if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) {
+            $groupusers = array_keys(groups_get_activity_shared_group_members($cm));
+            if (empty($groupusers)) {
+                return $updates;
+            }
+            list($insql, $inparams) = $DB->get_in_or_equal($groupusers);
+            $select .= ' AND userid ' . $insql;
+            $params = array_merge($params, $inparams);
+        }
+
+        $updates->userquestionattempts = (object) array('updated' => false);
+        $updates->usergrades = (object) array('updated' => false);
+        $updates->userpagesviewed = (object) array('updated' => false);
+        $updates->usertimers = (object) array('updated' => false);
+
+        $questionattempts = $DB->get_records_select('lesson_attempts', $select, $params, '', 'id');
+        if (!empty($questionattempts)) {
+            $updates->userquestionattempts->updated = true;
+            $updates->userquestionattempts->itemids = array_keys($questionattempts);
+        }
+        $pagesviewed = $DB->get_records_select('lesson_branch', $select, $params, '', 'id');
+        if (!empty($pagesviewed)) {
+            $updates->userpagesviewed->updated = true;
+            $updates->userpagesviewed->itemids = array_keys($pagesviewed);
+        }
+
+        $select = 'lessonid = ? AND completed > ? ' . $insql;
+        $grades = $DB->get_records_select('lesson_grades', $select, $params, '', 'id');
+        if (!empty($grades)) {
+            $updates->usergrades->updated = true;
+            $updates->usergrades->itemids = array_keys($grades);
+        }
+
+        $select = 'lessonid = ? AND (starttime > ? OR lessontime > ? OR timemodifiedoffline > ?) ' . $insql;
+        $params = array($cm->instance, $from, $from, $from);
+        $params = array_merge($params, $inparams);
+        $timers = $DB->get_records_select('lesson_timer', $select, $params, '', 'id');
+        if (!empty($timers)) {
+            $updates->usertimers->updated = true;
+            $updates->usertimers->itemids = array_keys($timers);
+        }
+    }
     return $updates;
 }
index a6f6455..213cf29 100644 (file)
@@ -604,6 +604,29 @@ function lti_check_updates_since(cm_info $cm, $from, $filter = array()) {
         $updates->submissions->itemids = array_keys($submissions);
     }
 
+    // Now, teachers should see other students updates.
+    if (has_capability('mod/lti:manage', $cm->context)) {
+        $select = 'ltiid = :id AND (datesubmitted > :since1 OR dateupdated > :since2)';
+        $params = array('id' => $cm->instance, 'since1' => $from, 'since2' => $from);
+
+        if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) {
+            $groupusers = array_keys(groups_get_activity_shared_group_members($cm));
+            if (empty($groupusers)) {
+                return $updates;
+            }
+            list($insql, $inparams) = $DB->get_in_or_equal($groupusers, SQL_PARAMS_NAMED);
+            $select .= ' AND userid ' . $insql;
+            $params = array_merge($params, $inparams);
+        }
+
+        $updates->usersubmissions = (object) array('updated' => false);
+        $submissions = $DB->get_records_select('lti_submission', $select, $params, '', 'id');
+        if (!empty($submissions)) {
+            $updates->usersubmissions->updated = true;
+            $updates->usersubmissions->itemids = array_keys($submissions);
+        }
+    }
+
     return $updates;
 }
 
index b91c369..d8aa858 100644 (file)
@@ -2048,6 +2048,35 @@ function quiz_check_updates_since(cm_info $cm, $from, $filter = array()) {
         $updates->grades->itemids = array_keys($grades);
     }
 
+    // Now, teachers should see other students updates.
+    if (has_capability('mod/quiz:viewreports', $cm->context)) {
+        $select = 'quiz = ? AND timemodified > ?';
+        $params = array($cm->instance, $from);
+
+        if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) {
+            $groupusers = array_keys(groups_get_activity_shared_group_members($cm));
+            if (empty($groupusers)) {
+                return $updates;
+            }
+            list($insql, $inparams) = $DB->get_in_or_equal($groupusers);
+            $select .= ' AND userid ' . $insql;
+            $params = array_merge($params, $inparams);
+        }
+
+        $updates->userattempts = (object) array('updated' => false);
+        $attempts = $DB->get_records_select('quiz_attempts', $select, $params, '', 'id');
+        if (!empty($attempts)) {
+            $updates->userattempts->updated = true;
+            $updates->userattempts->itemids = array_keys($attempts);
+        }
+
+        $updates->usergrades = (object) array('updated' => false);
+        $grades = $DB->get_records_select('quiz_grades', $select, $params, '', 'id');
+        if (!empty($grades)) {
+            $updates->usergrades->updated = true;
+            $updates->usergrades->itemids = array_keys($grades);
+        }
+    }
     return $updates;
 }
 
index b5a5bd0..041b914 100644 (file)
@@ -1525,6 +1525,29 @@ function scorm_check_updates_since(cm_info $cm, $from, $filter = array()) {
         $updates->tracks->updated = true;
         $updates->tracks->itemids = array_keys($tracks);
     }
+
+    // Now, teachers should see other students updates.
+    if (has_capability('mod/scorm:viewreport', $cm->context)) {
+        $select = 'scormid = ? AND timemodified > ?';
+        $params = array($scorm->id, $from);
+
+        if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) {
+            $groupusers = array_keys(groups_get_activity_shared_group_members($cm));
+            if (empty($groupusers)) {
+                return $updates;
+            }
+            list($insql, $inparams) = $DB->get_in_or_equal($groupusers);
+            $select .= ' AND userid ' . $insql;
+            $params = array_merge($params, $inparams);
+        }
+
+        $updates->usertracks = (object) array('updated' => false);
+        $tracks = $DB->get_records_select('scorm_scoes_track', $select, $params, '', 'id');
+        if (!empty($tracks)) {
+            $updates->usertracks->updated = true;
+            $updates->usertracks->itemids = array_keys($tracks);
+        }
+    }
     return $updates;
 }
 
index 73f67a6..2919ea9 100644 (file)
@@ -1072,5 +1072,28 @@ function survey_check_updates_since(cm_info $cm, $from, $filter = array()) {
         $updates->answers->updated = true;
         $updates->answers->itemids = array_keys($answers);
     }
+
+    // Now, teachers should see other students updates.
+    if (has_capability('mod/survey:readresponses', $cm->context)) {
+        $select = 'survey = ? AND time > ?';
+        $params = array($cm->instance, $from);
+
+        if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) {
+            $groupusers = array_keys(groups_get_activity_shared_group_members($cm));
+            if (empty($groupusers)) {
+                return $updates;
+            }
+            list($insql, $inparams) = $DB->get_in_or_equal($groupusers);
+            $select .= ' AND userid ' . $insql;
+            $params = array_merge($params, $inparams);
+        }
+
+        $updates->useranswers = (object) array('updated' => false);
+        $answers = $DB->get_records_select('survey_answers', $select, $params, '', 'id');
+        if (!empty($answers)) {
+            $updates->useranswers->updated = true;
+            $updates->useranswers->itemids = array_keys($answers);
+        }
+    }
     return $updates;
 }