Merge branch 'MDL-63542-35' of git://github.com/jleyva/moodle into MOODLE_35_STABLE

This commit is contained in:
Andrew Nicols 2018-10-15 11:32:50 +08:00
commit 2816fa5725
2 changed files with 118 additions and 26 deletions

View file

@ -56,6 +56,8 @@ class core_course_external extends external_api {
'The expected keys (value format) are: 'The expected keys (value format) are:
excludemodules (bool) Do not return modules, return only the sections structure excludemodules (bool) Do not return modules, return only the sections structure
excludecontents (bool) Do not return module contents (i.e: files inside a resource) excludecontents (bool) Do not return module contents (i.e: files inside a resource)
includestealthmodules (bool) Return stealth modules for students in a special
section (with id -1)
sectionid (int) Return only this section sectionid (int) Return only this section
sectionnumber (int) Return only this section with number (order) sectionnumber (int) Return only this section with number (order)
cmid (int) Return only this module information (among the whole sections structure) cmid (int) Return only this module information (among the whole sections structure)
@ -96,6 +98,7 @@ class core_course_external extends external_api {
switch ($name) { switch ($name) {
case 'excludemodules': case 'excludemodules':
case 'excludecontents': case 'excludecontents':
case 'includestealthmodules':
$value = clean_param($option['value'], PARAM_BOOL); $value = clean_param($option['value'], PARAM_BOOL);
$filters[$name] = $value; $filters[$name] = $value;
break; break;
@ -161,21 +164,12 @@ class core_course_external extends external_api {
$modinfo = get_fast_modinfo($course); $modinfo = get_fast_modinfo($course);
$sections = $modinfo->get_section_info_all(); $sections = $modinfo->get_section_info_all();
$coursenumsections = course_get_format($course)->get_last_section_number(); $coursenumsections = course_get_format($course)->get_last_section_number();
$stealthmodules = array(); // Array to keep all the modules available but not visible in a course section/topic.
//for each sections (first displayed to last displayed) //for each sections (first displayed to last displayed)
$modinfosections = $modinfo->get_sections(); $modinfosections = $modinfo->get_sections();
foreach ($sections as $key => $section) { foreach ($sections as $key => $section) {
// Show the section if the user is permitted to access it, OR if it's not available
// but there is some available info text which explains the reason & should display.
$showsection = $section->uservisible ||
($section->visible && !$section->available &&
!empty($section->availableinfo));
if (!$showsection) {
continue;
}
// This becomes true when we are filtering and we found the value to filter with. // This becomes true when we are filtering and we found the value to filter with.
$sectionfound = false; $sectionfound = false;
@ -216,8 +210,8 @@ class core_course_external extends external_api {
$sectioncontents = array(); $sectioncontents = array();
// For each module of the section (if it is visible). // For each module of the section.
if ($section->uservisible and empty($filters['excludemodules']) and !empty($modinfosections[$section->section])) { if (empty($filters['excludemodules']) and !empty($modinfosections[$section->section])) {
foreach ($modinfosections[$section->section] as $cmid) { foreach ($modinfosections[$section->section] as $cmid) {
$cm = $modinfo->cms[$cmid]; $cm = $modinfo->cms[$cmid];
@ -310,8 +304,13 @@ class core_course_external extends external_api {
} }
} }
//assign result to $sectioncontents // Assign result to $sectioncontents, there is an exception,
$sectioncontents[] = $module; // stealth activities in non-visible sections for students go to a special section.
if (!empty($filters['includestealthmodules']) && !$section->uservisible && $cm->is_stealth()) {
$stealthmodules[] = $module;
} else {
$sectioncontents[] = $module;
}
// If we just did a filtering, break the loop. // If we just did a filtering, break the loop.
if ($modfound) { if ($modfound) {
@ -323,13 +322,46 @@ class core_course_external extends external_api {
$sectionvalues['modules'] = $sectioncontents; $sectionvalues['modules'] = $sectioncontents;
// assign result to $coursecontents // assign result to $coursecontents
$coursecontents[] = $sectionvalues; $coursecontents[$key] = $sectionvalues;
// Break the loop if we are filtering. // Break the loop if we are filtering.
if ($sectionfound) { if ($sectionfound) {
break; break;
} }
} }
// Now that we have iterated over all the sections and activities, check the visibility.
// We didn't this before to be able to retrieve stealth activities.
foreach ($coursecontents as $sectionnumber => $sectioncontents) {
$section = $sections[$sectionnumber];
// Show the section if the user is permitted to access it, OR if it's not available
// but there is some available info text which explains the reason & should display.
$showsection = $section->uservisible ||
($section->visible && !$section->available &&
!empty($section->availableinfo));
if (!$showsection) {
unset($coursecontents[$sectionnumber]);
continue;
}
// Remove modules information if the section is not visible for the user.
if (!$section->uservisible) {
$coursecontents[$sectionnumber]['modules'] = array();
}
}
// Include stealth modules in special section (without any info).
if (!empty($stealthmodules)) {
$coursecontents[] = array(
'id' => -1,
'name' => '',
'summary' => '',
'summaryformat' => FORMAT_MOODLE,
'modules' => $stealthmodules
);
}
} }
return $coursecontents; return $coursecontents;
} }

View file

@ -806,8 +806,11 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
* @return array A list with the course object and course modules objects * @return array A list with the course object and course modules objects
*/ */
private function prepare_get_course_contents_test() { private function prepare_get_course_contents_test() {
global $DB; global $DB, $CFG;
$course = self::getDataGenerator()->create_course(['numsections' => 3]);
$CFG->allowstealth = 1; // Allow stealth activities.
$course = self::getDataGenerator()->create_course(['numsections' => 4]);
$forumdescription = 'This is the forum description'; $forumdescription = 'This is the forum description';
$forum = $this->getDataGenerator()->create_module('forum', $forum = $this->getDataGenerator()->create_module('forum',
array('course' => $course->id, 'intro' => $forumdescription), array('course' => $course->id, 'intro' => $forumdescription),
@ -817,6 +820,8 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
$datacm = get_coursemodule_from_instance('page', $data->id); $datacm = get_coursemodule_from_instance('page', $data->id);
$page = $this->getDataGenerator()->create_module('page', array('course' => $course->id)); $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
$pagecm = get_coursemodule_from_instance('page', $page->id); $pagecm = get_coursemodule_from_instance('page', $page->id);
// This is an stealth page (set by visibleoncoursepage).
$pagestealth = $this->getDataGenerator()->create_module('page', array('course' => $course->id, 'visibleoncoursepage' => 0));
$labeldescription = 'This is a very long label to test if more than 50 characters are returned. $labeldescription = 'This is a very long label to test if more than 50 characters are returned.
So bla bla bla bla <b>bold bold bold</b> bla bla bla bla.'; So bla bla bla bla <b>bold bold bold</b> bla bla bla bla.';
$label = $this->getDataGenerator()->create_module('label', array('course' => $course->id, $label = $this->getDataGenerator()->create_module('label', array('course' => $course->id,
@ -846,10 +851,18 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
$conditions = array('course' => $course->id, 'section' => 2); $conditions = array('course' => $course->id, 'section' => 2);
$DB->set_field('course_sections', 'summary', 'Text with iframe <iframe src="https://moodle.org"></iframe>', $conditions); $DB->set_field('course_sections', 'summary', 'Text with iframe <iframe src="https://moodle.org"></iframe>', $conditions);
// Add date availability condition not met for last section. // Add date availability condition not met for section 3.
$availability = '{"op":"&","c":[{"type":"date","d":">=","t":' . $tomorrow . '}],"showc":[true]}'; $availability = '{"op":"&","c":[{"type":"date","d":">=","t":' . $tomorrow . '}],"showc":[true]}';
$DB->set_field('course_sections', 'availability', $availability, $DB->set_field('course_sections', 'availability', $availability,
array('course' => $course->id, 'section' => 3)); array('course' => $course->id, 'section' => 3));
// Create resource for last section.
$pageinhiddensection = $this->getDataGenerator()->create_module('page',
array('course' => $course->id, 'name' => 'Page in hidden section', 'section' => 4));
// Set not visible last section.
$DB->set_field('course_sections', 'visible', 0,
array('course' => $course->id, 'section' => 4));
rebuild_course_cache($course->id, true); rebuild_course_cache($course->id, true);
return array($course, $forumcm, $datacm, $pagecm, $labelcm, $urlcm); return array($course, $forumcm, $datacm, $pagecm, $labelcm, $urlcm);
@ -863,6 +876,8 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
list($course, $forumcm, $datacm, $pagecm, $labelcm, $urlcm) = $this->prepare_get_course_contents_test(); list($course, $forumcm, $datacm, $pagecm, $labelcm, $urlcm) = $this->prepare_get_course_contents_test();
// We first run the test as admin.
$this->setAdminUser();
$sections = core_course_external::get_course_contents($course->id, array()); $sections = core_course_external::get_course_contents($course->id, array());
// We need to execute the return values cleaning process to simulate the web service server. // We need to execute the return values cleaning process to simulate the web service server.
$sections = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $sections); $sections = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $sections);
@ -889,21 +904,18 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
$this->assertEquals(2, $testexecuted); $this->assertEquals(2, $testexecuted);
$this->assertEquals(0, $sections[0]['section']); $this->assertEquals(0, $sections[0]['section']);
// Check that the only return section has the 5 created modules. $this->assertCount(5, $sections[0]['modules']);
$this->assertCount(4, $sections[0]['modules']);
$this->assertCount(1, $sections[1]['modules']); $this->assertCount(1, $sections[1]['modules']);
$this->assertCount(1, $sections[2]['modules']); $this->assertCount(1, $sections[2]['modules']);
$this->assertCount(0, $sections[3]['modules']); // No modules for the section with availability restrictions. $this->assertCount(1, $sections[3]['modules']); // One module for the section with availability restrictions.
$this->assertCount(1, $sections[4]['modules']); // One module for the hidden section with a visible activity.
$this->assertNotEmpty($sections[3]['availabilityinfo']); $this->assertNotEmpty($sections[3]['availabilityinfo']);
$this->assertEquals(1, $sections[1]['section']); $this->assertEquals(1, $sections[1]['section']);
$this->assertEquals(2, $sections[2]['section']); $this->assertEquals(2, $sections[2]['section']);
$this->assertEquals(3, $sections[3]['section']); $this->assertEquals(3, $sections[3]['section']);
$this->assertEquals(4, $sections[4]['section']);
$this->assertContains('<iframe', $sections[2]['summary']); $this->assertContains('<iframe', $sections[2]['summary']);
$this->assertContains('</iframe>', $sections[2]['summary']); $this->assertContains('</iframe>', $sections[2]['summary']);
// The module with the availability restriction met is returning contents.
$this->assertNotEmpty($sections[1]['modules'][0]['contents']);
// The module with the availability restriction not met is not returning contents.
$this->assertArrayNotHasKey('contents', $sections[2]['modules'][0]);
$this->assertNotEmpty($sections[2]['modules'][0]['availabilityinfo']); $this->assertNotEmpty($sections[2]['modules'][0]['availabilityinfo']);
try { try {
$sections = core_course_external::get_course_contents($course->id, $sections = core_course_external::get_course_contents($course->id,
@ -915,6 +927,54 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
} }
/**
* Test get_course_contents as student
*/
public function test_get_course_contents_student() {
global $DB;
$this->resetAfterTest(true);
list($course, $forumcm, $datacm, $pagecm, $labelcm, $urlcm) = $this->prepare_get_course_contents_test();
$studentroleid = $DB->get_field('role', 'id', array('shortname' => 'student'));
$user = self::getDataGenerator()->create_user();
self::getDataGenerator()->enrol_user($user->id, $course->id, $studentroleid);
$this->setUser($user);
$sections = core_course_external::get_course_contents($course->id, array());
// We need to execute the return values cleaning process to simulate the web service server.
$sections = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $sections);
$this->assertCount(4, $sections); // Nothing for the not visible section.
$this->assertCount(5, $sections[0]['modules']);
$this->assertCount(1, $sections[1]['modules']);
$this->assertCount(1, $sections[2]['modules']);
$this->assertCount(0, $sections[3]['modules']); // No modules for the section with availability restrictions.
$this->assertNotEmpty($sections[3]['availabilityinfo']);
$this->assertEquals(1, $sections[1]['section']);
$this->assertEquals(2, $sections[2]['section']);
$this->assertEquals(3, $sections[3]['section']);
// The module with the availability restriction met is returning contents.
$this->assertNotEmpty($sections[1]['modules'][0]['contents']);
// The module with the availability restriction not met is not returning contents.
$this->assertArrayNotHasKey('contents', $sections[2]['modules'][0]);
// Now include flag for returning stealth information (fake section).
$sections = core_course_external::get_course_contents($course->id,
array(array("name" => "includestealthmodules", "value" => 1)));
// We need to execute the return values cleaning process to simulate the web service server.
$sections = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $sections);
$this->assertCount(5, $sections); // Include fake section with stealth activities.
$this->assertCount(5, $sections[0]['modules']);
$this->assertCount(1, $sections[1]['modules']);
$this->assertCount(1, $sections[2]['modules']);
$this->assertCount(0, $sections[3]['modules']); // No modules for the section with availability restrictions.
$this->assertCount(1, $sections[4]['modules']); // One stealh module.
$this->assertEquals(-1, $sections[4]['id']);
}
/** /**
* Test get_course_contents excluding modules * Test get_course_contents excluding modules
*/ */
@ -972,7 +1032,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
$sections = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $sections); $sections = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $sections);
$this->assertCount(1, $sections); $this->assertCount(1, $sections);
$this->assertCount(4, $sections[0]['modules']); $this->assertCount(5, $sections[0]['modules']);
} }
/** /**