diff --git a/blocks/classes/external.php b/blocks/classes/external.php new file mode 100644 index 00000000000..95de3b808e9 --- /dev/null +++ b/blocks/classes/external.php @@ -0,0 +1,137 @@ +. + +/** + * Blocks external API + * + * @package core_block + * @category external + * @copyright 2017 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 3.3 + */ + +defined('MOODLE_INTERNAL') || die; + +require_once("$CFG->libdir/externallib.php"); + +/** + * Blocks external functions + * + * @package core_block + * @category external + * @copyright 2015 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 3.3 + */ +class core_block_external extends external_api { + + /** + * Returns description of get_course_blocks parameters. + * + * @return external_function_parameters + * @since Moodle 3.3 + */ + public static function get_course_blocks_parameters() { + return new external_function_parameters( + array( + 'courseid' => new external_value(PARAM_INT, 'course id') + ) + ); + } + + /** + * Returns blocks information for a course. + * + * @param int $courseid The course id + * @return array Blocks list and possible warnings + * @throws moodle_exception + * @since Moodle 3.3 + */ + public static function get_course_blocks($courseid) { + global $OUTPUT, $PAGE; + + $warnings = array(); + $params = self::validate_parameters(self::get_course_blocks_parameters(), ['courseid' => $courseid]); + + $course = get_course($params['courseid']); + $context = context_course::instance($course->id); + self::validate_context($context); + + // Specific layout for frontpage course. + if ($course->id == SITEID) { + $PAGE->set_pagelayout('frontpage'); + $PAGE->set_pagetype('site-index'); + } else { + $PAGE->set_pagelayout('course'); + // Ensure course format is set (view course/view.php). + $course->format = course_get_format($course)->get_format(); + $PAGE->set_pagetype('course-view-' . $course->format); + } + + // Load the block instances for all the regions. + $PAGE->blocks->load_blocks(); + $PAGE->blocks->create_all_block_instances(); + + $finalblocks = array(); + $blocks = $PAGE->blocks->get_content_for_all_regions($OUTPUT); + foreach ($blocks as $region => $regionblocks) { + foreach ($regionblocks as $bc) { + $finalblocks[] = [ + 'instanceid' => $bc->blockinstanceid, + 'name' => $bc->attributes['data-block'], + 'region' => $region, + 'positionid' => $bc->blockpositionid, + 'collapsible' => (bool) $bc->collapsible, + 'dockable' => (bool) $bc->dockable, + ]; + } + } + + return array( + 'blocks' => $finalblocks, + 'warnings' => $warnings + ); + } + + /** + * Returns description of get_course_blocks result values. + * + * @return external_single_structure + * @since Moodle 3.3 + */ + public static function get_course_blocks_returns() { + + return new external_single_structure( + array( + 'blocks' => new external_multiple_structure( + new external_single_structure( + array( + 'instanceid' => new external_value(PARAM_INT, 'Block instance id.'), + 'name' => new external_value(PARAM_PLUGIN, 'Block name.'), + 'region' => new external_value(PARAM_ALPHANUMEXT, 'Block region.'), + 'positionid' => new external_value(PARAM_INT, 'Position id.'), + 'collapsible' => new external_value(PARAM_BOOL, 'Whether the block is collapsible.'), + 'dockable' => new external_value(PARAM_BOOL, 'hether the block is dockable.'), + ), 'Block information.' + ), 'List of blocks in the course.' + ), + 'warnings' => new external_warnings(), + ) + ); + } + +} diff --git a/blocks/tests/externallib_test.php b/blocks/tests/externallib_test.php new file mode 100644 index 00000000000..fdf3bea560b --- /dev/null +++ b/blocks/tests/externallib_test.php @@ -0,0 +1,141 @@ +. + +/** + * External block functions unit tests + * + * @package core_block + * @category external + * @copyright 2017 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 3.3 + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +require_once($CFG->dirroot . '/webservice/tests/helpers.php'); + +/** + * External block functions unit tests + * + * @package core_block + * @category external + * @copyright 2015 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 3.0 + */ +class core_block_externallib_testcase extends externallib_advanced_testcase { + + /** + * Test get_course_blocks + */ + public function test_get_course_blocks() { + global $DB, $FULLME; + + $this->resetAfterTest(true); + + $user = $this->getDataGenerator()->create_user(); + $course = $this->getDataGenerator()->create_course(); + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id); + + $page = new moodle_page(); + $page->set_context(context_course::instance($course->id)); + $page->set_pagelayout('course'); + $course->format = course_get_format($course)->get_format(); + $page->set_pagetype('course-view-' . $course->format); + $page->blocks->load_blocks(); + $newblock = 'calendar_upcoming'; + $page->blocks->add_block_at_end_of_default_region($newblock); + $this->setUser($user); + + // Check for the new block. + $result = core_block_external::get_course_blocks($course->id); + // We need to execute the return values cleaning process to simulate the web service server. + $result = external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result); + + // Expect the new block. + $this->assertCount(1, $result['blocks']); + $this->assertEquals($newblock, $result['blocks'][0]['name']); + } + + /** + * Test get_course_blocks on site home + */ + public function test_get_course_blocks_site_home() { + global $DB, $FULLME; + + $this->resetAfterTest(true); + + $user = $this->getDataGenerator()->create_user(); + + $page = new moodle_page(); + $page->set_context(context_course::instance(SITEID)); + $page->set_pagelayout('frontpage'); + $page->set_pagetype('site-index'); + $page->blocks->load_blocks(); + $newblock = 'calendar_upcoming'; + $page->blocks->add_block_at_end_of_default_region($newblock); + $this->setUser($user); + + // Check for the new block. + $result = core_block_external::get_course_blocks(SITEID); + // We need to execute the return values cleaning process to simulate the web service server. + $result = external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result); + + // Expect the new block. + $this->assertCount(1, $result['blocks']); + $this->assertEquals($newblock, $result['blocks'][0]['name']); + } + + /** + * Test get_course_blocks + */ + public function test_get_course_blocks_overrides() { + global $DB, $CFG, $FULLME; + + $this->resetAfterTest(true); + + $CFG->defaultblocks_override = 'participants,search_forums,course_list:calendar_upcoming,recent_activity'; + + $user = $this->getDataGenerator()->create_user(); + $course = $this->getDataGenerator()->create_course(); + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id); + + $this->setUser($user); + + // Try default blocks. + $result = core_block_external::get_course_blocks($course->id); + // We need to execute the return values cleaning process to simulate the web service server. + $result = external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result); + + // Expect 5 default blocks. + $this->assertCount(5, $result['blocks']); + + $expectedblocks = array('navigation', 'settings', 'participants', 'search_forums', 'course_list', + 'calendar_upcoming', 'recent_activity'); + foreach ($result['blocks'] as $block) { + if (!in_array($block['name'], $expectedblocks)) { + $this->fail("Unexpected block found: " . $block['name']); + } + } + + } + +} diff --git a/lib/blocklib.php b/lib/blocklib.php index 296c55d4bba..5f11639cdca 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -319,6 +319,24 @@ class block_manager { return $this->visibleblockcontent[$region]; } + /** + * Returns an array of block content objects for all the existings regions + * + * @param renderer_base $output the rendered to use + * @return array of block block_contents objects for all the blocks in all regions. + * @since Moodle 3.3 + */ + public function get_content_for_all_regions($output) { + $contents = array(); + $this->check_is_loaded(); + + foreach ($this->regions as $region => $val) { + $this->ensure_content_created($region, $output); + $contents[$region] = $this->visibleblockcontent[$region]; + } + return $contents; + } + /** * Helper method used by get_content_for_region. * @param string $region region name diff --git a/lib/db/services.php b/lib/db/services.php index 5ff30cdef28..058c452402b 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -1912,7 +1912,17 @@ $functions = array( 'description' => 'Return some site info / user info / list web service functions', 'type' => 'read', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), - ) + ), + + // Blocks functions. + 'core_block_get_course_blocks' => array( + 'classname' => 'core_block_external', + 'methodname' => 'get_course_blocks', + 'description' => 'Returns blocks information for a course.', + 'type' => 'read', + 'capabilities' => '', + 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), + ), ); $services = array( diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4b9ac502627..7d801485dfa 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -148,6 +148,9 @@ auth/tests + + blocks/tests + diff --git a/version.php b/version.php index f8fd9032855..8a5f4a2be68 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2017033100.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2017033100.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes.