Merge branch 'MDL-78088-master' of https://github.com/jleyva/moodle
[moodle.git] / blocks / tests / externallib_test.php
blob5d5b92784d660c0d7a950f1892f5f147f13e52d5
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 namespace core_block;
19 use core_block_external;
20 use externallib_advanced_testcase;
22 defined('MOODLE_INTERNAL') || die();
24 global $CFG;
26 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
27 require_once($CFG->dirroot . '/my/lib.php');
29 /**
30 * External block functions unit tests
32 * @package core_block
33 * @category external
34 * @copyright 2015 Juan Leyva <juan@moodle.com>
35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 * @since Moodle 3.0
38 class externallib_test extends externallib_advanced_testcase {
40 /**
41 * Test get_course_blocks
43 public function test_get_course_blocks() {
44 global $DB, $FULLME;
46 $this->resetAfterTest(true);
48 $user = $this->getDataGenerator()->create_user();
49 $course = $this->getDataGenerator()->create_course();
50 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
51 $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
53 $page = new \moodle_page();
54 $page->set_context(\context_course::instance($course->id));
55 $page->set_pagelayout('course');
56 $course->format = course_get_format($course)->get_format();
57 $page->set_pagetype('course-view-' . $course->format);
58 $page->blocks->load_blocks();
59 $newblock = 'calendar_upcoming';
60 $page->blocks->add_block_at_end_of_default_region($newblock);
61 $this->setUser($user);
63 // Check for the new block.
64 $result = core_block_external::get_course_blocks($course->id);
65 // We need to execute the return values cleaning process to simulate the web service server.
66 $result = \core_external\external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
68 // Expect the new block.
69 $this->assertCount(1, $result['blocks']);
70 $this->assertEquals($newblock, $result['blocks'][0]['name']);
73 /**
74 * Test get_course_blocks on site home
76 public function test_get_course_blocks_site_home() {
77 global $DB, $FULLME;
79 $this->resetAfterTest(true);
81 $user = $this->getDataGenerator()->create_user();
83 $page = new \moodle_page();
84 $page->set_context(\context_course::instance(SITEID));
85 $page->set_pagelayout('frontpage');
86 $page->set_pagetype('site-index');
87 $page->blocks->load_blocks();
88 $newblock = 'calendar_upcoming';
89 $page->blocks->add_block_at_end_of_default_region($newblock);
90 $this->setUser($user);
92 // Check for the new block.
93 $result = core_block_external::get_course_blocks(SITEID);
94 // We need to execute the return values cleaning process to simulate the web service server.
95 $result = \core_external\external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
97 // Expect the new block.
98 $this->assertCount(1, $result['blocks']);
99 $this->assertEquals($newblock, $result['blocks'][0]['name']);
103 * Test get_course_blocks
105 public function test_get_course_blocks_overrides() {
106 global $DB, $CFG, $FULLME;
108 $this->resetAfterTest(true);
110 $CFG->defaultblocks_override = 'search_forums,course_list:calendar_upcoming,recent_activity';
112 $user = $this->getDataGenerator()->create_user();
113 $course = $this->getDataGenerator()->create_course();
114 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
115 $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
117 $this->setUser($user);
119 // Try default blocks.
120 $result = core_block_external::get_course_blocks($course->id);
121 // We need to execute the return values cleaning process to simulate the web service server.
122 $result = \core_external\external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
124 // Expect 4 default blocks.
125 $this->assertCount(4, $result['blocks']);
127 $expectedblocks = array('navigation', 'settings', 'search_forums', 'course_list',
128 'calendar_upcoming', 'recent_activity');
129 foreach ($result['blocks'] as $block) {
130 if (!in_array($block['name'], $expectedblocks)) {
131 $this->fail("Unexpected block found: " . $block['name']);
138 * Test get_course_blocks contents
140 public function test_get_course_blocks_contents() {
141 global $DB, $FULLME;
143 $this->resetAfterTest(true);
145 $user = $this->getDataGenerator()->create_user();
146 $course = $this->getDataGenerator()->create_course();
147 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
148 $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
149 $coursecontext = \context_course::instance($course->id);
151 // Create a HTML block.
152 $title = 'Some course info';
153 $body = 'Some course info<br /><p>Some contents</p>';
154 $bodyformat = FORMAT_MOODLE;
155 $page = new \moodle_page();
156 $page->set_context($coursecontext);
157 $page->set_pagelayout('course');
158 $course->format = course_get_format($course)->get_format();
159 $page->set_pagetype('course-view-' . $course->format);
160 $page->blocks->load_blocks();
161 $newblock = 'html';
162 $page->blocks->add_block_at_end_of_default_region($newblock);
164 $this->setUser($user);
165 // Re-create the page.
166 $page = new \moodle_page();
167 $page->set_context($coursecontext);
168 $page->set_pagelayout('course');
169 $course->format = course_get_format($course)->get_format();
170 $page->set_pagetype('course-view-' . $course->format);
171 $page->blocks->load_blocks();
172 $blocks = $page->blocks->get_blocks_for_region($page->blocks->get_default_region());
173 $block = end($blocks);
174 $block = block_instance('html', $block->instance);
175 $nonscalar = [
176 'something' => true,
178 $configdata = (object) [
179 'title' => $title,
180 'text' => [
181 'itemid' => 0,
182 'text' => $body,
183 'format' => $bodyformat,
185 'nonscalar' => $nonscalar
187 $block->instance_config_save((object) $configdata);
188 $filename = 'img.png';
189 $filerecord = array(
190 'contextid' => \context_block::instance($block->instance->id)->id,
191 'component' => 'block_html',
192 'filearea' => 'content',
193 'itemid' => 0,
194 'filepath' => '/',
195 'filename' => $filename,
197 // Create an area to upload the file.
198 $fs = get_file_storage();
199 // Create a file from the string that we made earlier.
200 $file = $fs->create_file_from_string($filerecord, 'some fake content (should be an image).');
202 // Check for the new block.
203 $result = core_block_external::get_course_blocks($course->id, true);
204 // We need to execute the return values cleaning process to simulate the web service server.
205 $result = \core_external\external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
207 // Expect the new block.
208 $this->assertCount(1, $result['blocks']);
209 $this->assertEquals($title, $result['blocks'][0]['contents']['title']);
210 $this->assertEquals($body, $result['blocks'][0]['contents']['content']);
211 $this->assertEquals(FORMAT_HTML, $result['blocks'][0]['contents']['contentformat']); // Format change for external.
212 $this->assertEquals('', $result['blocks'][0]['contents']['footer']);
213 $this->assertCount(1, $result['blocks'][0]['contents']['files']);
214 $this->assertEquals($newblock, $result['blocks'][0]['name']);
215 $configcounts = 0;
216 foreach ($result['blocks'][0]['configs'] as $config) {
217 if ($config['type'] = 'plugin' && $config['name'] == 'allowcssclasses' && $config['value'] == json_encode('0')) {
218 $configcounts++;
219 } else if ($config['type'] = 'instance' && $config['name'] == 'text' && $config['value'] == json_encode($body)) {
220 $configcounts++;
221 } else if ($config['type'] = 'instance' && $config['name'] == 'title' && $config['value'] == json_encode($title)) {
222 $configcounts++;
223 } else if ($config['type'] = 'instance' && $config['name'] == 'format' && $config['value'] == json_encode('0')) {
224 $configcounts++;
225 } else if ($config['type'] = 'instance' && $config['name'] == 'nonscalar' &&
226 $config['value'] == json_encode($nonscalar)) {
227 $configcounts++;
230 $this->assertEquals(5, $configcounts);
234 * Test get_course_blocks contents with mathjax.
236 public function test_get_course_blocks_contents_with_mathjax() {
237 global $DB, $CFG;
239 $this->resetAfterTest(true);
241 // Enable MathJax filter in content and headings.
242 $this->configure_filters([
243 ['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true],
246 // Create a few stuff to test with.
247 $user = $this->getDataGenerator()->create_user();
248 $course = $this->getDataGenerator()->create_course();
249 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
250 $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
251 $coursecontext = \context_course::instance($course->id);
253 // Create a HTML block.
254 $title = 'My block $$(a+b)=2$$';
255 $body = 'My block contents $$(a+b)=2$$';
256 $bodyformat = FORMAT_MOODLE;
257 $page = new \moodle_page();
258 $page->set_context($coursecontext);
259 $page->set_pagelayout('course');
260 $course->format = course_get_format($course)->get_format();
261 $page->set_pagetype('course-view-' . $course->format);
262 $page->blocks->load_blocks();
263 $newblock = 'html';
264 $page->blocks->add_block_at_end_of_default_region($newblock);
266 $this->setUser($user);
267 // Re-create the page.
268 $page = new \moodle_page();
269 $page->set_context($coursecontext);
270 $page->set_pagelayout('course');
271 $course->format = course_get_format($course)->get_format();
272 $page->set_pagetype('course-view-' . $course->format);
273 $page->blocks->load_blocks();
274 $blocks = $page->blocks->get_blocks_for_region($page->blocks->get_default_region());
275 $block = end($blocks);
276 $block = block_instance('html', $block->instance);
277 $nonscalar = [
278 'something' => true,
280 $configdata = (object) [
281 'title' => $title,
282 'text' => [
283 'itemid' => 0,
284 'text' => $body,
285 'format' => $bodyformat,
287 'nonscalar' => $nonscalar
289 $block->instance_config_save((object) $configdata);
291 // Check for the new block.
292 $result = core_block_external::get_course_blocks($course->id, true);
293 $result = \core_external\external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
295 // Format the original data.
296 $sitecontext = \context_system::instance();
297 $title = \core_external\util::format_string($title, $coursecontext->id);
298 list($body, $bodyformat) = \core_external\util::format_text($body, $bodyformat, $coursecontext, 'block_html', 'content');
300 // Check that the block data is formatted.
301 $this->assertCount(1, $result['blocks']);
302 $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">',
303 $result['blocks'][0]['contents']['title']);
304 $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">',
305 $result['blocks'][0]['contents']['content']);
306 $this->assertEquals($title, $result['blocks'][0]['contents']['title']);
307 $this->assertEquals($body, $result['blocks'][0]['contents']['content']);
311 * Test user get default dashboard blocks.
313 public function test_get_dashboard_blocks_default_dashboard() {
314 global $PAGE, $DB;
315 $this->resetAfterTest(true);
317 $user = $this->getDataGenerator()->create_user();
318 $PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
320 // Force a setting change to check the returned blocks settings.
321 set_config('displaycategories', 0, 'block_myoverview');
323 $systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => MY_PAGE_DEFAULT, 'private' => true));
324 // Get the expected default blocks.
325 $alldefaultblocksordered = $DB->get_records_menu(
326 'block_instances',
327 array('pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id),
328 'defaultregion, defaultweight ASC',
329 'id, blockname'
332 $this->setUser($user);
334 // Check for the default blocks.
335 $result = core_block_external::get_dashboard_blocks($user->id);
336 // We need to execute the return values cleaning process to simulate the web service server.
337 $result = \core_external\external_api::clean_returnvalue(core_block_external::get_dashboard_blocks_returns(), $result);
338 // Expect all default blocks defined in blocks_add_default_system_blocks().
339 $this->assertCount(count($alldefaultblocksordered), $result['blocks']);
340 $returnedblocks = array();
341 foreach ($result['blocks'] as $block) {
342 // Check all the returned blocks are in the expected blocks array.
343 $this->assertContains($block['name'], $alldefaultblocksordered);
344 $returnedblocks[] = $block['name'];
345 // Check the configuration returned for this default block.
346 if ($block['name'] == 'myoverview') {
347 // Convert config to associative array to avoid DB sorting randomness.
348 $config = array_column($block['configs'], null, 'name');
349 $this->assertArrayHasKey('displaycategories', $config);
350 $this->assertEquals(json_encode('0'), $config['displaycategories']['value']);
351 $this->assertEquals('plugin', $config['displaycategories']['type']);
355 // Check that we received the blocks in the expected order.
356 $this->assertEquals(array_values($alldefaultblocksordered), $returnedblocks);
360 * Test user get default dashboard blocks including a sticky block.
362 public function test_get_dashboard_blocks_default_dashboard_including_sticky_block() {
363 global $PAGE, $DB;
364 $this->resetAfterTest(true);
366 $user = $this->getDataGenerator()->create_user();
367 $PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
369 $systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => MY_PAGE_DEFAULT, 'private' => true));
370 // Get the expected default blocks.
371 $alldefaultblocks = $DB->get_records_menu(
372 'block_instances', array('pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id),
374 'id, blockname'
377 // Now, add a sticky block.
378 $page = new \moodle_page();
379 $page->set_context(\context_system::instance());
380 $page->set_pagetype('my-index');
381 $page->set_url(new \moodle_url('/'));
382 $page->blocks->add_region('side-pre');
383 $page->blocks->load_blocks();
384 $page->blocks->add_block('myprofile', 'side-pre', 0, true, '*');
386 $this->setUser($user);
388 // Check for the default blocks plus the sticky.
389 $result = core_block_external::get_dashboard_blocks($user->id);
390 // We need to execute the return values cleaning process to simulate the web service server.
391 $result = \core_external\external_api::clean_returnvalue(core_block_external::get_dashboard_blocks_returns(), $result);
392 // Expect all default blocks defined in blocks_add_default_system_blocks() plus sticky one.
393 $this->assertCount(count($alldefaultblocks) + 1, $result['blocks']);
394 $found = false;
395 foreach ($result['blocks'] as $block) {
396 if ($block['name'] == 'myprofile') {
397 $this->assertEquals('side-pre', $block['region']);
398 $found = true;
399 continue;
401 // Check that the block is in the expected blocks array.
402 $this->assertContains($block['name'], $alldefaultblocks);
404 $this->assertTrue($found);
408 * Test admin get user's custom dashboard blocks.
410 public function test_get_dashboard_blocks_custom_user_dashboard() {
411 global $PAGE, $DB;
412 $this->resetAfterTest(true);
414 $user = $this->getDataGenerator()->create_user();
415 $PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
417 $systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => MY_PAGE_DEFAULT, 'private' => true));
418 // Get the expected default blocks.
419 $alldefaultblocks = $DB->get_records_menu(
420 'block_instances',
421 array('pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id),
423 'id, blockname'
426 // Add a custom block.
427 $page = new \moodle_page();
428 $page->set_context(\context_user::instance($user->id));
429 $page->set_pagelayout('mydashboard');
430 $page->set_pagetype('my-index');
431 $page->blocks->add_region('content');
432 $currentpage = my_get_page($user->id, MY_PAGE_PRIVATE);
433 $page->set_subpage($currentpage->id);
434 $page->blocks->load_blocks();
435 $page->blocks->add_block('myprofile', 'content', 0, false);
437 $this->setAdminUser();
439 // Check for the new block as admin for a user.
440 $result = core_block_external::get_dashboard_blocks($user->id);
441 // We need to execute the return values cleaning process to simulate the web service server.
442 $result = \core_external\external_api::clean_returnvalue(core_block_external::get_dashboard_blocks_returns(), $result);
443 // Expect all default blocks defined in blocks_add_default_system_blocks() plus the one we added.
444 $this->assertCount(count($alldefaultblocks) + 1, $result['blocks']);
445 $found = false;
446 foreach ($result['blocks'] as $block) {
447 if ($block['name'] == 'myprofile') {
448 $this->assertEquals('content', $block['region']);
449 $found = true;
450 continue;
452 // Check that the block is in the expected blocks array.
453 $this->assertContains($block['name'], $alldefaultblocks);
455 $this->assertTrue($found);
459 * Test user tries to get other user blocks not having permission.
461 public function test_get_dashboard_blocks_other_user_missing_permissions() {
462 $this->resetAfterTest(true);
464 $user1 = $this->getDataGenerator()->create_user();
465 $user2 = $this->getDataGenerator()->create_user();
467 $this->setUser($user1);
469 $this->expectException('moodle_exception');
470 core_block_external::get_dashboard_blocks($user2->id);
474 * Test user get default dashboard blocks for my courses page.
476 public function test_get_dashboard_blocks_my_courses() {
477 global $PAGE, $DB;
478 $this->resetAfterTest(true);
480 $user = $this->getDataGenerator()->create_user();
481 $PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
483 // Force a setting change to check the returned blocks settings.
484 set_config('displaycategories', 0, 'block_myoverview');
486 $systempage = $DB->get_record('my_pages', ['userid' => null, 'name' => MY_PAGE_COURSES, 'private' => false]);
487 // Get the expected default blocks.
488 $alldefaultblocksordered = $DB->get_records_menu(
489 'block_instances',
490 ['pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id],
491 'defaultregion, defaultweight ASC',
492 'id, blockname'
495 $this->setUser($user);
497 // Check for the default blocks.
498 $result = core_block_external::get_dashboard_blocks($user->id, false, MY_PAGE_COURSES);
499 // We need to execute the return values cleaning process to simulate the web service server.
500 $result = \core_external\external_api::clean_returnvalue(core_block_external::get_dashboard_blocks_returns(), $result);
501 // Expect all default blocks defined in blocks_add_default_system_blocks().
502 $this->assertCount(count($alldefaultblocksordered), $result['blocks']);
503 $returnedblocks = [];
504 foreach ($result['blocks'] as $block) {
505 // Check all the returned blocks are in the expected blocks array.
506 $this->assertContains($block['name'], $alldefaultblocksordered);
507 $returnedblocks[] = $block['name'];
508 // Check the configuration returned for this default block.
509 if ($block['name'] == 'myoverview') {
510 // Convert config to associative array to avoid DB sorting randomness.
511 $config = array_column($block['configs'], null, 'name');
512 $this->assertArrayHasKey('displaycategories', $config);
513 $this->assertEquals(json_encode('0'), $config['displaycategories']['value']);
514 $this->assertEquals('plugin', $config['displaycategories']['type']);
518 // Check that we received the blocks in the expected order.
519 $this->assertEquals(array_values($alldefaultblocksordered), $returnedblocks);
523 * Test user passing the wrong page type and getting an exception.
525 public function test_get_dashboard_blocks_incorrect_page() {
526 global $PAGE;
527 $this->resetAfterTest(true);
529 $user = $this->getDataGenerator()->create_user();
530 $PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
532 $this->setUser($user);
534 $this->expectException('moodle_exception');
535 // Check for the default blocks with a fake page, no need to assign as it'll throw.
536 core_block_external::get_dashboard_blocks($user->id, false, 'fakepage');