diff --git a/course/classes/search/customfield.php b/course/classes/search/customfield.php index 19fa1c251cd..faeaa721b7a 100644 --- a/course/classes/search/customfield.php +++ b/course/classes/search/customfield.php @@ -126,18 +126,34 @@ class customfield extends \core_search\base { /** * Whether the user can access the document or not. * - * @param int $id The course instance id. + * @param int $id The custom field data ID * @return int */ public function check_access($id) { global $DB; - $course = $DB->get_record('course', array('id' => $id)); + + $coursesql = ' + SELECT c.* + FROM {course} c + JOIN {customfield_data} d ON d.instanceid = c.id + WHERE d.id = :dataid'; + + // Verify both the course and data record still exist. + $course = $DB->get_record_sql($coursesql, ['dataid' => $id]); if (!$course) { return \core_search\manager::ACCESS_DELETED; } - if (\core_course_category::can_view_course_info($course)) { + + // Check whether user is enrolled and the course is visible, or user can view it while hidden. + $context = \context_course::instance($course->id); + $userenrolled = is_enrolled($context) && + ($course->visible || has_capability('moodle/course:viewhiddencourses', $context)); + + // Grant access if user is considered enrolled, or they can otherwise see the course info. + if ($userenrolled || \core_course_category::can_view_course_info($course)) { return \core_search\manager::ACCESS_GRANTED; } + return \core_search\manager::ACCESS_DENIED; } diff --git a/course/tests/search_test.php b/course/tests/search_test.php index f438ee1dac6..44e14277265 100644 --- a/course/tests/search_test.php +++ b/course/tests/search_test.php @@ -542,6 +542,8 @@ class course_search_testcase extends advanced_testcase { * Document accesses for customfield area. */ public function test_customfield_access() { + global $DB; + $this->resetAfterTest(); // Returns the instance as long as the area is supported. @@ -550,25 +552,62 @@ class course_search_testcase extends advanced_testcase { $user1 = self::getDataGenerator()->create_user(); $user2 = self::getDataGenerator()->create_user(); - $course1 = self::getDataGenerator()->create_course(); - $course2 = self::getDataGenerator()->create_course(array('visible' => 0)); - $course3 = self::getDataGenerator()->create_course(); + // Create our custom field. + $customfieldcategory = $this->getDataGenerator()->create_custom_field_category([]); + $customfield = $this->getDataGenerator()->create_custom_field([ + 'categoryid' => $customfieldcategory->get('id'), + 'type' => 'text', + 'shortname' => 'myfield', + ]); + + // Create courses, each containing our custom field. + $course1 = $this->getDataGenerator()->create_course(['customfield_myfield' => 'Lionel']); + $course2 = $this->getDataGenerator()->create_course(['customfield_myfield' => 'Rick', 'visible' => 0]); + $course3 = $this->getDataGenerator()->create_course(['customfield_myfield' => 'Jack']); $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'teacher'); $this->getDataGenerator()->enrol_user($user2->id, $course1->id, 'student'); $this->getDataGenerator()->enrol_user($user1->id, $course2->id, 'teacher'); $this->getDataGenerator()->enrol_user($user2->id, $course2->id, 'student'); - $this->setUser($user1); - $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course1->id)); - $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course2->id)); - $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course3->id)); + // Prevent users viewing course lists. + $userrole = $DB->get_field('role', 'id', ['shortname' => 'user'], MUST_EXIST); + assign_capability('moodle/category:viewcourselist', CAP_PREVENT, $userrole, context_system::instance()->id, true); + + // The following assertions check whether each user can view the indexed customfield data record. + $course1data = \core_customfield\data::get_record([ + 'fieldid' => $customfield->get('id'), + 'instanceid' => $course1->id, + ]); + $course2data = \core_customfield\data::get_record([ + 'fieldid' => $customfield->get('id'), + 'instanceid' => $course2->id, + ]); + $course3data = \core_customfield\data::get_record([ + 'fieldid' => $customfield->get('id'), + 'instanceid' => $course3->id, + ]); + + // Admin user should see all present custom fields. + $this->setAdminUser(); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course1data->get('id'))); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course2data->get('id'))); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course3data->get('id'))); $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-123)); + // First user (teacher) should see all those in the courses they are teaching. + $this->setUser($user1); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course1data->get('id'))); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course2data->get('id'))); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($course3data->get('id'))); + $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-123)); + + // Second user (student) should see all those in visible courses they are studying. $this->setUser($user2); - $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course1->id)); - $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($course2->id)); - $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course3->id)); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($course1data->get('id'))); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($course2data->get('id'))); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($course3data->get('id'))); + $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-123)); } /**