From 794604db6d797e7923064087141771a18a3f73b5 Mon Sep 17 00:00:00 2001 From: Mihail Geshoski Date: Tue, 21 May 2019 11:35:26 +0800 Subject: [PATCH 1/3] MDL-65653 book: Display hidden chapters in WS when user has capability --- course/externallib.php | 1 + mod/book/lib.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/course/externallib.php b/course/externallib.php index 7f3a170a75b..d2ba0205416 100644 --- a/course/externallib.php +++ b/course/externallib.php @@ -489,6 +489,7 @@ class core_course_external extends external_api { VALUE_OPTIONAL), 'repositorytype' => new external_value(PARAM_PLUGIN, 'The repository type for external files.', VALUE_OPTIONAL), + 'ishidden' => new external_value(PARAM_BOOL, 'Whether the content is hidden.', VALUE_OPTIONAL), // copyright related info 'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'), diff --git a/mod/book/lib.php b/mod/book/lib.php index 0b4887f80ba..bfd5223e3cc 100644 --- a/mod/book/lib.php +++ b/mod/book/lib.php @@ -570,7 +570,7 @@ function book_export_contents($cm, $baseurl) { $currentchapter = 0; foreach ($chapters as $chapter) { - if ($chapter->hidden) { + if ($chapter->hidden && !has_capability('mod/book:viewhiddenchapters', $context)) { continue; } @@ -612,6 +612,7 @@ function book_export_contents($cm, $baseurl) { $chapterindexfile['author'] = null; $chapterindexfile['license'] = null; $chapterindexfile['tags'] = \core_tag\external\util::get_item_tags('mod_book', 'book_chapters', $chapter->id); + $chapterindexfile['ishidden'] = (bool) $chapter->hidden; $contents[] = $chapterindexfile; // Chapter files (images usually). From 89d8dec35ffda105f1d9d3086d8b8bbfa2899486 Mon Sep 17 00:00:00 2001 From: Mihail Geshoski Date: Tue, 21 May 2019 11:32:07 +0800 Subject: [PATCH 2/3] MDL-65653 book: Update unit tests --- mod/book/tests/lib_test.php | 81 +++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/mod/book/tests/lib_test.php b/mod/book/tests/lib_test.php index 49f740a5b6d..7f9ff401946 100644 --- a/mod/book/tests/lib_test.php +++ b/mod/book/tests/lib_test.php @@ -49,9 +49,13 @@ class mod_book_lib_testcase extends advanced_testcase { require_once($CFG->dirroot . '/course/externallib.php'); $user = $this->getDataGenerator()->create_user(); + $teacher = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(array('enablecomment' => 1)); $studentrole = $DB->get_record('role', array('shortname' => 'student')); + $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); + $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id); + $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id); // Test book with 3 chapters. $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id)); @@ -75,18 +79,95 @@ class mod_book_lib_testcase extends advanced_testcase { $this->assertEquals('structure', $contents[0]['filename']); $this->assertEquals('index.html', $contents[1]['filename']); $this->assertEquals('Chapter 1', $contents[1]['content']); + $this->assertFalse($contents[1]['ishidden']); $this->assertCount(2, $contents[1]['tags']); $this->assertEquals('Cats', $contents[1]['tags'][0]['rawname']); $this->assertEquals($tag->id, $contents[1]['tags'][0]['id']); $this->assertEquals('Dogs', $contents[1]['tags'][1]['rawname']); $this->assertEquals('index.html', $contents[2]['filename']); $this->assertEquals('Chapter 2', $contents[2]['content']); + $this->assertFalse($contents[2]['ishidden']); $this->assertEquals('index.html', $contents[3]['filename']); $this->assertEquals('Chapter 3', $contents[3]['content']); + $this->assertFalse($contents[3]['ishidden']); // Now, test the function via the external API. $contents = core_course_external::get_course_contents($course->id, array()); $contents = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $contents); + + $this->assertCount(4, $contents[0]['modules'][0]['contents']); + + $this->assertEquals('content', $contents[0]['modules'][0]['contents'][0]['type']); + $this->assertEquals('structure', $contents[0]['modules'][0]['contents'][0]['filename']); + + $this->assertEquals('file', $contents[0]['modules'][0]['contents'][1]['type']); + $this->assertEquals('Chapter 1', $contents[0]['modules'][0]['contents'][1]['content']); + $this->assertFalse($contents[0]['modules'][0]['contents'][1]['ishidden']); + + $this->assertEquals('file', $contents[0]['modules'][0]['contents'][2]['type']); + $this->assertEquals('Chapter 2', $contents[0]['modules'][0]['contents'][2]['content']); + $this->assertFalse($contents[0]['modules'][0]['contents'][2]['ishidden']); + + $this->assertEquals('file', $contents[0]['modules'][0]['contents'][3]['type']); + $this->assertEquals('Chapter 3', $contents[0]['modules'][0]['contents'][3]['content']); + $this->assertFalse($contents[0]['modules'][0]['contents'][3]['ishidden']); + + $this->assertEquals('book', $contents[0]['modules'][0]['modname']); + $this->assertEquals($cm->id, $contents[0]['modules'][0]['id']); + $this->assertCount(2, $contents[0]['modules'][0]['contents'][1]['tags']); + $this->assertEquals('Cats', $contents[0]['modules'][0]['contents'][1]['tags'][0]['rawname']); + $this->assertEquals('Dogs', $contents[0]['modules'][0]['contents'][1]['tags'][1]['rawname']); + + // As a teacher. + $this->setUser($teacher); + + $contents = book_export_contents($cm, ''); + // As a teacher, the hidden chapter must be included, and additional page with the structure must be included. + $this->assertCount(5, $contents); + + $this->assertEquals('structure', $contents[0]['filename']); + $this->assertEquals('index.html', $contents[1]['filename']); + $this->assertEquals('Chapter 1', $contents[1]['content']); + $this->assertFalse($contents[1]['ishidden']); + $this->assertCount(2, $contents[1]['tags']); + $this->assertEquals('Cats', $contents[1]['tags'][0]['rawname']); + $this->assertEquals($tag->id, $contents[1]['tags'][0]['id']); + $this->assertEquals('Dogs', $contents[1]['tags'][1]['rawname']); + $this->assertEquals('index.html', $contents[2]['filename']); + $this->assertEquals('Chapter 2', $contents[2]['content']); + $this->assertFalse($contents[2]['ishidden']); + $this->assertEquals('index.html', $contents[3]['filename']); + $this->assertEquals('Chapter 3', $contents[3]['content']); + $this->assertFalse($contents[3]['ishidden']); + $this->assertEquals('index.html', $contents[4]['filename']); + $this->assertEquals('Chapter 4', $contents[4]['content']); + $this->assertTrue($contents[4]['ishidden']); + + // Now, test the function via the external API. + $contents = core_course_external::get_course_contents($course->id, array()); + $contents = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $contents); + + $this->assertCount(5, $contents[0]['modules'][0]['contents']); + + $this->assertEquals('content', $contents[0]['modules'][0]['contents'][0]['type']); + $this->assertEquals('structure', $contents[0]['modules'][0]['contents'][0]['filename']); + + $this->assertEquals('file', $contents[0]['modules'][0]['contents'][1]['type']); + $this->assertEquals('Chapter 1', $contents[0]['modules'][0]['contents'][1]['content']); + $this->assertFalse($contents[0]['modules'][0]['contents'][1]['ishidden']); + + $this->assertEquals('file', $contents[0]['modules'][0]['contents'][2]['type']); + $this->assertEquals('Chapter 2', $contents[0]['modules'][0]['contents'][2]['content']); + $this->assertFalse($contents[0]['modules'][0]['contents'][2]['ishidden']); + + $this->assertEquals('file', $contents[0]['modules'][0]['contents'][3]['type']); + $this->assertEquals('Chapter 3', $contents[0]['modules'][0]['contents'][3]['content']); + $this->assertFalse($contents[0]['modules'][0]['contents'][3]['ishidden']); + + $this->assertEquals('file', $contents[0]['modules'][0]['contents'][4]['type']); + $this->assertEquals('Chapter 4', $contents[0]['modules'][0]['contents'][4]['content']); + $this->assertTrue($contents[0]['modules'][0]['contents'][4]['ishidden']); + $this->assertEquals('book', $contents[0]['modules'][0]['modname']); $this->assertEquals($cm->id, $contents[0]['modules'][0]['id']); $this->assertCount(2, $contents[0]['modules'][0]['contents'][1]['tags']); From d0342c8ec9e5ef4a3cb032353d60a0de383dcb04 Mon Sep 17 00:00:00 2001 From: Juan Leyva Date: Thu, 15 Aug 2019 14:01:27 +0100 Subject: [PATCH 3/3] MDL-65653 book: Display hidden chapters in the structure content --- course/externallib.php | 1 - mod/book/lib.php | 2 +- mod/book/tests/lib_test.php | 35 ++++++++++++++++++++--------------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/course/externallib.php b/course/externallib.php index d2ba0205416..7f3a170a75b 100644 --- a/course/externallib.php +++ b/course/externallib.php @@ -489,7 +489,6 @@ class core_course_external extends external_api { VALUE_OPTIONAL), 'repositorytype' => new external_value(PARAM_PLUGIN, 'The repository type for external files.', VALUE_OPTIONAL), - 'ishidden' => new external_value(PARAM_BOOL, 'Whether the content is hidden.', VALUE_OPTIONAL), // copyright related info 'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'), diff --git a/mod/book/lib.php b/mod/book/lib.php index bfd5223e3cc..7aab091e09d 100644 --- a/mod/book/lib.php +++ b/mod/book/lib.php @@ -579,6 +579,7 @@ function book_export_contents($cm, $baseurl) { "title" => format_string($chapter->title, true, array('context' => $context)), "href" => $chapter->id . "/index.html", "level" => 0, + "hidden" => $chapter->hidden, "subitems" => array() ); @@ -612,7 +613,6 @@ function book_export_contents($cm, $baseurl) { $chapterindexfile['author'] = null; $chapterindexfile['license'] = null; $chapterindexfile['tags'] = \core_tag\external\util::get_item_tags('mod_book', 'book_chapters', $chapter->id); - $chapterindexfile['ishidden'] = (bool) $chapter->hidden; $contents[] = $chapterindexfile; // Chapter files (images usually). diff --git a/mod/book/tests/lib_test.php b/mod/book/tests/lib_test.php index 7f9ff401946..247f29dda93 100644 --- a/mod/book/tests/lib_test.php +++ b/mod/book/tests/lib_test.php @@ -79,17 +79,14 @@ class mod_book_lib_testcase extends advanced_testcase { $this->assertEquals('structure', $contents[0]['filename']); $this->assertEquals('index.html', $contents[1]['filename']); $this->assertEquals('Chapter 1', $contents[1]['content']); - $this->assertFalse($contents[1]['ishidden']); $this->assertCount(2, $contents[1]['tags']); $this->assertEquals('Cats', $contents[1]['tags'][0]['rawname']); $this->assertEquals($tag->id, $contents[1]['tags'][0]['id']); $this->assertEquals('Dogs', $contents[1]['tags'][1]['rawname']); $this->assertEquals('index.html', $contents[2]['filename']); $this->assertEquals('Chapter 2', $contents[2]['content']); - $this->assertFalse($contents[2]['ishidden']); $this->assertEquals('index.html', $contents[3]['filename']); $this->assertEquals('Chapter 3', $contents[3]['content']); - $this->assertFalse($contents[3]['ishidden']); // Now, test the function via the external API. $contents = core_course_external::get_course_contents($course->id, array()); @@ -102,15 +99,12 @@ class mod_book_lib_testcase extends advanced_testcase { $this->assertEquals('file', $contents[0]['modules'][0]['contents'][1]['type']); $this->assertEquals('Chapter 1', $contents[0]['modules'][0]['contents'][1]['content']); - $this->assertFalse($contents[0]['modules'][0]['contents'][1]['ishidden']); $this->assertEquals('file', $contents[0]['modules'][0]['contents'][2]['type']); $this->assertEquals('Chapter 2', $contents[0]['modules'][0]['contents'][2]['content']); - $this->assertFalse($contents[0]['modules'][0]['contents'][2]['ishidden']); $this->assertEquals('file', $contents[0]['modules'][0]['contents'][3]['type']); $this->assertEquals('Chapter 3', $contents[0]['modules'][0]['contents'][3]['content']); - $this->assertFalse($contents[0]['modules'][0]['contents'][3]['ishidden']); $this->assertEquals('book', $contents[0]['modules'][0]['modname']); $this->assertEquals($cm->id, $contents[0]['modules'][0]['id']); @@ -122,26 +116,32 @@ class mod_book_lib_testcase extends advanced_testcase { $this->setUser($teacher); $contents = book_export_contents($cm, ''); - // As a teacher, the hidden chapter must be included, and additional page with the structure must be included. + // As a teacher, the hidden chapter must be included in the structure. $this->assertCount(5, $contents); $this->assertEquals('structure', $contents[0]['filename']); + // Check structure is correct. + $foundhiddenchapter = false; + $chapters = json_decode($contents[0]['content']); + foreach ($chapters as $chapter) { + if ($chapter->title == 'Chapter 4' && $chapter->hidden == 1) { + $foundhiddenchapter = true; + } + } + $this->assertTrue($foundhiddenchapter); + $this->assertEquals('index.html', $contents[1]['filename']); $this->assertEquals('Chapter 1', $contents[1]['content']); - $this->assertFalse($contents[1]['ishidden']); $this->assertCount(2, $contents[1]['tags']); $this->assertEquals('Cats', $contents[1]['tags'][0]['rawname']); $this->assertEquals($tag->id, $contents[1]['tags'][0]['id']); $this->assertEquals('Dogs', $contents[1]['tags'][1]['rawname']); $this->assertEquals('index.html', $contents[2]['filename']); $this->assertEquals('Chapter 2', $contents[2]['content']); - $this->assertFalse($contents[2]['ishidden']); $this->assertEquals('index.html', $contents[3]['filename']); $this->assertEquals('Chapter 3', $contents[3]['content']); - $this->assertFalse($contents[3]['ishidden']); $this->assertEquals('index.html', $contents[4]['filename']); $this->assertEquals('Chapter 4', $contents[4]['content']); - $this->assertTrue($contents[4]['ishidden']); // Now, test the function via the external API. $contents = core_course_external::get_course_contents($course->id, array()); @@ -151,22 +151,27 @@ class mod_book_lib_testcase extends advanced_testcase { $this->assertEquals('content', $contents[0]['modules'][0]['contents'][0]['type']); $this->assertEquals('structure', $contents[0]['modules'][0]['contents'][0]['filename']); + // Check structure is correct. + $foundhiddenchapter = false; + $chapters = json_decode($contents[0]['modules'][0]['contents'][0]['content']); + foreach ($chapters as $chapter) { + if ($chapter->title == 'Chapter 4' && $chapter->hidden == 1) { + $foundhiddenchapter = true; + } + } + $this->assertTrue($foundhiddenchapter); $this->assertEquals('file', $contents[0]['modules'][0]['contents'][1]['type']); $this->assertEquals('Chapter 1', $contents[0]['modules'][0]['contents'][1]['content']); - $this->assertFalse($contents[0]['modules'][0]['contents'][1]['ishidden']); $this->assertEquals('file', $contents[0]['modules'][0]['contents'][2]['type']); $this->assertEquals('Chapter 2', $contents[0]['modules'][0]['contents'][2]['content']); - $this->assertFalse($contents[0]['modules'][0]['contents'][2]['ishidden']); $this->assertEquals('file', $contents[0]['modules'][0]['contents'][3]['type']); $this->assertEquals('Chapter 3', $contents[0]['modules'][0]['contents'][3]['content']); - $this->assertFalse($contents[0]['modules'][0]['contents'][3]['ishidden']); $this->assertEquals('file', $contents[0]['modules'][0]['contents'][4]['type']); $this->assertEquals('Chapter 4', $contents[0]['modules'][0]['contents'][4]['content']); - $this->assertTrue($contents[0]['modules'][0]['contents'][4]['ishidden']); $this->assertEquals('book', $contents[0]['modules'][0]['modname']); $this->assertEquals($cm->id, $contents[0]['modules'][0]['id']);